Django-Admin: CharField come TextArea


88

io ho

class Cab(models.Model):
    name  = models.CharField( max_length=20 )
    descr = models.CharField( max_length=2000 )

class Cab_Admin(admin.ModelAdmin):
    ordering     = ('name',)
    list_display = ('name','descr', )
    # what to write here to make descr using TextArea?

admin.site.register( Cab, Cab_Admin )

come assegnare il widget TextArea al campo "descr" nell'interfaccia di amministrazione?

aggiornamento:
in Admin solo l'interfaccia!

Buona idea usare ModelForm.


3
La risposta accettata è enorme eccessivo ai fini della modifica di un solo campo! Persone seguono questa risposta da Carl Meyer PER SCOPO DELLA SEMPLICITÀ: stackoverflow.com/questions/430592/...
andilabs

Risposte:


99

Dovrai creare un forms.ModelFormche descriverà come vuoi che il descrcampo venga visualizzato, e poi dire admin.ModelAdmindi usare quel modulo. Per esempio:

from django import forms
class CabModelForm( forms.ModelForm ):
    descr = forms.CharField( widget=forms.Textarea )
    class Meta:
        model = Cab

class Cab_Admin( admin.ModelAdmin ):
    form = CabModelForm

L' formattributo di admin.ModelAdminè documentato nella documentazione ufficiale di Django. Ecco un posto da guardare .


6
Per sostituire semplicemente un widget modulo, non è necessario creare l'intero modulo. Puoi semplicemente sovrascrivere formfield_for_dbfieldil tuo ModelAdmin, vedere la mia risposta di seguito.
Carl Meyer

1
Questo dàdjango.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu

4
A partire da Django 1.7 è necessario aggiungere anche fields = '__all__'sotto class Meta:.
skoll

2
Non è necessario creare il modulo da soli, è possibile sovrascrivere il get_formmetodo. Vedi la mia risposta .
x-yuri

L'approccio di beeter consiste nell'usare Meta class Meta: model = Message widgets = {'text': forms.Textarea (attrs = {'cols': 80, 'rows': 20}),}
Amulya Acharya

58

In questo caso, l'opzione migliore è probabilmente solo quella di utilizzare un TextField invece di CharField nel tuo modello. Puoi anche sovrascrivere il formfield_for_dbfieldmetodo della tua ModelAdminclasse:

class CabAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(CabAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'descr':
            formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)
        return formfield

c'è qualche svantaggio in questo rispetto alla risposta selezionata? questo sembra più pulito da implementare in quanto non è necessario creare un nuovo ModelForm ...
Filipe Pina

3
sostituito formfield.widget = forms.Textarea()con formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)per mantenere tutti gli attributi generati automaticamente per TextField, grazie!
Filipe Pina

2
Non so perché l'altra risposta sia accettata rispetto a questa; Penso che se tutto ciò che stai facendo è sostituire un widget, questo è più semplice. Ma entrambi funzioneranno bene.
Carl Meyer

Ha funzionato perfettamente, grazie. L'invocazione super () sembra un po 'prolissa, c'è un modo più semplice per farlo?
rjh

2
@rjh In py3 puoi eliminare tutto all'interno delle parentesi e usarlo super(). Altrimenti no.
Carl Meyer

33

Ayaz ha praticamente azzeccato, tranne per un leggero cambiamento (?!):

class MessageAdminForm(forms.ModelForm):
    class Meta:
        model = Message
        widgets = {
            'text': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
        }

class MessageAdmin(admin.ModelAdmin):
    form = MessageAdminForm
admin.site.register(Message, MessageAdmin)

Quindi, non è necessario ridefinire un campo nel ModelForm per modificarne il widget, è sufficiente impostare il comando dei widget in Meta.


1
Questo mantiene più proprietà "automatiche" rispetto alla risposta di Ayaz, ma qualche consiglio su come mantenere anche la convalida della lunghezza del campo?
Filipe Pina

14

Puoi sottoclassare il tuo campo con il formfieldmetodo necessario :

class CharFieldWithTextarea(models.CharField):

    def formfield(self, **kwargs):
        kwargs.update({"widget": forms.Textarea})
        return super(CharFieldWithTextarea, self).formfield(**kwargs)

Ciò avrà effetto su tutti i moduli generati.


9

Non è necessario creare da soli la classe del modulo:

from django.contrib import admin
from django import forms

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['widgets'] = {'descr': forms.Textarea}
        return super().get_form(request, obj, **kwargs)

admin.site.register(MyModel, MyModelAdmin)

Vedi ModelAdmin.get_form .


7

Invece di un models.CharField, usa un models.TextFieldper descr.


4
Sfortunatamente, max_length = è totalmente ignorato da Django su un TextField, quindi quando è necessaria la convalida della lunghezza del campo (come lasciare che le segretarie inseriscano i riepiloghi degli eventi) l'unico modo per ottenerlo è usare un CharField. Ma un CharField è troppo breve per digitare 300 caratteri. Da qui la soluzione ayaz.
shacker

3
Questa non è una buona risposta perché cambia il database. Lo scopo di cambiare il widget è cambiare la modalità di visualizzazione del campo, non cambiare lo schema del database

1
È un'ottima risposta per qualcuno (come me) che sta imparando a usare Django e avrebbe impostato il database in modo diverso in primo luogo se avessi saputo meglio.
Andrew Swift

7

Se stai cercando di cambiare la Textarea su admin.py, questa è la soluzione che ha funzionato per me:

from django import forms
from django.contrib import admin
from django.db import models
from django.forms import TextInput, Textarea

from books.models import Book

class BookForm(forms.ModelForm):
    description = forms.CharField( widget=forms.Textarea(attrs={'rows': 5, 'cols': 100}))
    class Meta:
        model = Book

class BookAdmin(admin.ModelAdmin):
    form = BookForm

admin.site.register(Book, BookAdmin)

Se stai usando un database MySQL, la lunghezza della tua colonna sarà solitamente impostata automaticamente su 250 caratteri, quindi ti consigliamo di eseguire un ALTER TABLE per modificare la lunghezza nel tuo DB MySQL, in modo da poter sfruttare la nuova Textarea più grande che tu avere nel tuo sito Admin Django.


5

Puoi usare models.TextFielda questo scopo:

class Sample(models.Model):
    field1 = models.CharField(max_length=128)
    field2 = models.TextField(max_length=1024*2)   # Will be rendered as textarea

3
Questo cambierà la struttura del DB, quindi
fai

3

Volevo espandere la risposta di Carl Meyer, che funziona perfettamente fino a questa data.

Uso sempre TextFieldinvece di CharField(con o senza scelte) e impongo limiti di caratteri sul lato UI / API piuttosto che a livello di DB. Per fare in modo che funzioni dinamicamente:

from django import forms
from django.contrib import admin


class BaseAdmin(admin.ModelAdmin):
    """
    Base admin capable of forcing widget conversion
    """
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(BaseAdmin, self).formfield_for_dbfield(
            db_field, **kwargs)

        display_as_charfield = getattr(self, 'display_as_charfield', [])
        display_as_choicefield = getattr(self, 'display_as_choicefield', [])

        if db_field.name in display_as_charfield:
            formfield.widget = forms.TextInput(attrs=formfield.widget.attrs)
        elif db_field.name in display_as_choicefield:
            formfield.widget = forms.Select(choices=formfield.choices,
                                            attrs=formfield.widget.attrs)

        return formfield

Ho un nome del modello Postin cui title, sluge statesono TextFields ed stateha scelte. La definizione dell'amministratore ha il seguente aspetto:

@admin.register(Post)
class PostAdmin(BaseAdmin):
    list_display = ('pk', 'title', 'author', 'org', 'state', 'created',)
    search_fields = [
        'title',
        'author__username',
    ]
    display_as_charfield = ['title', 'slug']
    display_as_choicefield = ['state']

Ho pensato che altri in cerca di risposte potrebbero trovarlo utile.


È formfield_for_dbfielddocumentato?
x-yuri
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.