Django-Admin: CharField sebagai TextArea

88

saya sudah

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 )

bagaimana cara menetapkan widget TextArea ke bidang 'descr' di antarmuka admin?

upd: Hanya
dalam antarmuka Admin !

Ide bagus untuk menggunakan ModelForm.

maks
sumber
3
Jawaban yang diterima terlalu berlebihan untuk tujuan modifikasi hanya dalam satu bidang! ORANG IKUTI JAWABAN INI oleh Carl Meyer UNTUK TUJUAN
SEDERHANA

Jawaban:

99

Anda harus membuat forms.ModelFormyang akan menjelaskan bagaimana Anda ingin descrbidang tersebut ditampilkan, dan kemudian memberitahu admin.ModelAdminuntuk menggunakan formulir itu. Sebagai contoh:

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

The formatribut admin.ModelAdmindidokumentasikan dalam dokumentasi Django resmi. Inilah satu tempat untuk dilihat .

ayaz
sumber
6
Untuk hanya mengganti widget formulir, Anda tidak perlu membuat seluruh formulir Anda sendiri. Anda bisa menimpa formfield_for_dbfieldAnda ModelAdmin, lihat jawaban saya di bawah ini.
Carl Meyer
1
Ini memberidjango.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu
4
Mulai dari Django 1.7 Anda perlu menambahkan juga di fields = '__all__'bawah class Meta:.
skoll
2
Anda tidak perlu membuat formulir sendiri, Anda dapat mengganti get_formmetode. Lihat jawaban saya .
x-yuri
Pendekatan yang lebih baik adalah menggunakan kelas Meta Meta: model = Message widgets = {'text': forms.Textarea (attrs = {'cols': 80, 'row': 20}),}
Amulya Acharya
58

Untuk kasus ini, opsi terbaik mungkin hanya menggunakan TextField daripada CharField di model Anda. Anda juga dapat mengganti formfield_for_dbfieldmetode ModelAdminkelas Anda :

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
sumber
apakah ada kerugian dalam hal ini dibandingkan dengan jawaban yang dipilih? ini terlihat lebih bersih untuk diterapkan karena kita tidak perlu membuat ModelForm baru ...
Filipe Pina
3
diganti formfield.widget = forms.Textarea()dengan formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)untuk menjaga semua atribut secara otomatis dibuat untuk BidangTeks, Terima kasih!
Filipe Pina
2
Saya tidak tahu mengapa jawaban lain diterima atas yang ini; Saya pikir jika semua yang Anda lakukan adalah mengganti widget, ini lebih sederhana. Tapi keduanya akan bekerja dengan baik.
Carl Meyer
Ini bekerja dengan sempurna, terima kasih. Doa super () tampaknya sedikit bertele-tele, apakah ada cara yang lebih sederhana untuk melakukannya?
rjh
2
@rjh Dalam py3 Anda dapat menghilangkan semua yang ada di dalam parens dan hanya menggunakan super(). Jika tidak, tidak.
Carl Meyer
33

Ayaz memiliki banyak posisi, kecuali untuk sedikit perubahan (?!):

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)

Jadi, Anda tidak perlu mendefinisikan ulang bidang di ModelForm untuk mengubah widgetnya, cukup setel dikt widget di Meta.

Gezim
sumber
1
Ini memang mempertahankan lebih banyak properti "otomatis" daripada jawaban Ayaz, tetapi ada tip tentang cara menjaga validasi panjang bidang juga?
Filipe Pina
14

Anda dapat membuat subkelas bidang Anda sendiri dengan formfieldmetode yang diperlukan :

class CharFieldWithTextarea(models.CharField):

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

Ini akan mempengaruhi semua formulir yang dihasilkan.

Alex Koshelev
sumber
9

Anda tidak perlu membuat kelas formulir sendiri:

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)

Lihat ModelAdmin.get_form .

x-yuri
sumber
7

Daripada a models.CharField, gunakan models.TextFielduntuk descr.

mipadi
sumber
4
Sayangnya, max_length = benar-benar diabaikan oleh Django pada TextField, jadi ketika Anda membutuhkan validasi panjang field (seperti membiarkan sekretaris memasukkan ringkasan event) satu-satunya cara untuk mendapatkannya adalah dengan menggunakan CharField. Tapi CharField adalah cara singkat untuk mengetik 300 karakter. Karenanya solusi ayaz.
shacker
3
Ini bukan jawaban yang bagus karena mengubah database. Inti dari mengubah widget adalah untuk mengubah cara bidang ditampilkan, bukan untuk mengubah skema database
1
Itu adalah jawaban yang bagus untuk seseorang (seperti saya) yang belajar bagaimana menggunakan Django dan akan mengatur database secara berbeda di tempat pertama jika saya tahu lebih baik.
Andrew Swift
7

Jika Anda mencoba mengubah Textarea di admin.py, ini solusi yang berhasil untuk saya:

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)

Jika Anda menggunakan MySQL DB, panjang kolom Anda biasanya akan disetel otomatis menjadi 250 karakter, jadi Anda perlu menjalankan ALTER TABLE untuk mengubah panjang MySQL DB Anda, sehingga Anda dapat memanfaatkan Textarea baru yang lebih besar yang Anda gunakan. ada di situs Admin Django Anda.

Aaron Lelevier
sumber
5

Anda dapat menggunakan models.TextFielduntuk tujuan ini:

class Sample(models.Model):
    field1 = models.CharField(max_length=128)
    field2 = models.TextField(max_length=1024*2)   # Will be rendered as textarea
vk-kode
sumber
3
Ini akan mengubah struktur DB jadi hati
elad silver
3

Ingin memperluas jawaban Carl Meyer, yang bekerja dengan sempurna hingga saat ini.

Saya selalu menggunakan TextFieldalih-alih CharField(dengan atau tanpa pilihan) dan memaksakan batas karakter di sisi UI / API daripada di tingkat DB. Untuk membuat ini bekerja secara dinamis:

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

Saya memiliki nama model Postwhere title, slug& stateare TextFields dan statememiliki pilihan. Definisi admin terlihat seperti:

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

Pikir orang lain yang mencari jawaban mungkin menganggap ini berguna.

tarequeh.dll
sumber
Apakah ini formfield_for_dbfielddidokumentasikan?
x-yuri