Django-Admin: CharField als TextArea

87

ich habe

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 )

Wie ordne ich das TextArea-Widget dem Feld "Beschreibung" in der Administrationsoberfläche zu?

upd: Nur
in der Admin- Oberfläche!

Gute Idee, ModelForm zu verwenden.

maxp
quelle
3
Die akzeptierte Antwort ist ein riesiger Overkill zum Zweck der Modifizierung nur eines Feldes! MENSCHEN FOLGEN DIESER ANTWORT von Carl Meyer ZUR EINFACHHEIT: stackoverflow.com/questions/430592/…
andilabs

Antworten:

98

Sie müssen eine erstellen forms.ModelForm, die beschreibt, wie das descrFeld angezeigt werden soll, und dann anweisen admin.ModelAdmin, dieses Formular zu verwenden. Beispielsweise:

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

Das formAttribut von admin.ModelAdminist in der offiziellen Django-Dokumentation dokumentiert. Hier ist ein Ort zum Anschauen .

Ayaz
quelle
6
Zum einfachen Ersetzen eines Formular-Widgets müssen Sie nicht Ihr gesamtes Formular erstellen. Sie können einfach formfield_for_dbfieldIhre überschreiben ModelAdmin, siehe meine Antwort unten.
Carl Meyer
1
Dies gibtdjango.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu
4
Ab Django 1.7 müssen Sie auch fields = '__all__'unter hinzufügen class Meta:.
Skoll
2
Sie müssen das Formular nicht selbst erstellen, sondern können die get_formMethode überschreiben . Siehe meine Antwort .
X-Yuri
Beeter-Ansatz ist die Verwendung der Meta-Klasse Meta: model = Message widgets = {'text': forms.Textarea (attrs = {'cols': 80, '
rows
57

In diesem Fall ist es wahrscheinlich die beste Option, in Ihrem Modell nur ein TextField anstelle von CharField zu verwenden. Sie können auch die formfield_for_dbfieldMethode Ihrer ModelAdminKlasse überschreiben :

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
Carl Meyer
quelle
Gibt es einen Nachteil im Vergleich zur ausgewählten Antwort? Die Implementierung sieht sauberer aus, da wir kein neues ModelForm erstellen müssen ...
Filipe Pina
3
ersetzt formfield.widget = forms.Textarea()durch formfield.widget = forms.Textarea(attrs=formfield.widget.attrs), damit alle Attribute automatisch für das TextField generiert werden. Danke!
Filipe Pina
2
Ich weiß nicht, warum die andere Antwort über diese akzeptiert wird; Ich denke, wenn Sie nur ein Widget ersetzen, ist dies einfacher. Aber beides wird gut funktionieren.
Carl Meyer
Das hat perfekt funktioniert, danke. Der Aufruf von super () scheint allerdings etwas ausführlich zu sein. Gibt es einen einfacheren Weg, dies zu tun?
rjh
2
@rjh In py3 kannst du alles in den Parens eliminieren und einfach benutzen super(). Sonst nein.
Carl Meyer
32

Ayaz hat ziemlich genau das Richtige, bis auf eine kleine Änderung (?!):

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)

Sie müssen also kein Feld in der ModelForm neu definieren, um das Widget zu ändern. Legen Sie einfach das Widget-Diktat in Meta fest.

Gezim
quelle
1
Dies behält mehr "automatische" Eigenschaften bei als Ayaz 'Antwort, aber gibt es auch einen Tipp, wie die Validierung der Feldlänge beibehalten werden kann?
Filipe Pina
14

Sie können Ihr eigenes Feld mit der erforderlichen formfieldMethode unterordnen:

class CharFieldWithTextarea(models.CharField):

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

Dies wirkt sich auf alle generierten Formulare aus.

Alex Koshelev
quelle
9

Sie müssen die Formularklasse nicht selbst erstellen:

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)

Siehe ModelAdmin.get_form .

x-yuri
quelle
7

Wenn Sie versuchen, den Textbereich auf admin.py zu ändern, ist dies die Lösung, die für mich funktioniert hat:

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)

Wenn Sie eine MySQL-Datenbank verwenden, wird Ihre Spaltenlänge normalerweise automatisch auf 250 Zeichen festgelegt. Sie sollten daher eine ALTER TABLE ausführen, um die Länge in Ihrer MySQL-Datenbank zu ändern, damit Sie den neuen größeren Textbereich nutzen können, den Sie verwenden habe in dir Admin Django Seite.

Aaron Lelevier
quelle
6

models.CharFieldVerwenden Sie anstelle von a ein models.TextFieldfür descr.

Mipadi
quelle
4
Leider wird max_length = von Django in einem TextField vollständig ignoriert. Wenn Sie also eine Feldlängenüberprüfung benötigen (z. B. Sekretäre Ereigniszusammenfassungen eingeben lassen), können Sie dies nur mithilfe eines CharFields erreichen. Ein CharField ist jedoch viel zu kurz, um 300 Zeichen einzugeben. Daher die Ayaz-Lösung.
Shacker
3
Dies ist keine gute Antwort, da dadurch die Datenbank geändert wird. Der
1
Es ist eine großartige Antwort für jemanden (wie mich), der lernt, wie man Django benutzt und die Datenbank an erster Stelle anders eingerichtet hätte, wenn ich es besser gewusst hätte.
Andrew Swift
5

Sie können models.TextFieldfür diesen Zweck verwenden:

class Sample(models.Model):
    field1 = models.CharField(max_length=128)
    field2 = models.TextField(max_length=1024*2)   # Will be rendered as textarea
vk-code
quelle
3
Dies wird die DB-Struktur ändern, seien Sie also vorsichtig
elad Silber
3

Wollte Carl Meyers Antwort erweitern, die bis heute perfekt funktioniert.

Ich verwende immer TextFieldanstelle von CharField(mit oder ohne Auswahlmöglichkeiten) und lege Zeichenbeschränkungen eher auf der UI / API-Seite als auf DB-Ebene fest. Damit dies dynamisch funktioniert:

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

Ich habe einen Modellnamen , Postwo title, slugund statesind TextFields und statehat Entscheidungen. Die Admin-Definition sieht folgendermaßen aus:

@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']

Dachte, andere, die nach Antworten suchen, könnten dies nützlich finden.

Tarequeh
quelle
Ist das formfield_for_dbfielddokumentiert?
X-Yuri