Django-Admin: CharField як TextArea


87

У мене є

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 )

як призначити віджет TextArea для поля 'descr' в інтерфейсі адміністратора?

upd:
Тільки в інтерфейсі адміністратора !

Хороша ідея використовувати ModelForm.


3
Прийнята відповідь є величезним надмірним для модифікації лише одного поля! Люди йдуть ця відповідь Карл Майєр ДЛЯ ПРОВЕДЕННЯ простота: stackoverflow.com/questions/430592 / ...
andilabs

Відповіді:


99

Вам доведеться створити, forms.ModelFormякий описуватиме, як ви хочете, щоб descrполе відображалося, а потім наказав admin.ModelAdminвикористовувати цю форму. Наприклад:

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

formАтрибут admin.ModelAdminдокументована в офіційній документації Django. Ось одне місце, на яке слід подивитися .


6
Для простої заміни віджета форми вам не потрібно створювати всю власну форму. Ви можете просто відмінити formfield_for_dbfieldсвій ModelAdmin, див. Мою відповідь нижче.
Carl Meyer

1
Це даєdjango.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
John Wu

4
Починаючи з Django 1.7, вам потрібно додати також fields = '__all__'під class Meta:.
skoll

2
Вам не потрібно створювати форму самостійно, ви можете замінити get_formметод. Дивіться мою відповідь .
x-yuri

Кращий підхід полягає у використанні мета-класу Meta: model = Віджети повідомлень = {'text': forms.Textarea (attrs = {'cols': 80, 'рядки': 20}),}
Amulya Acharya

58

У цьому випадку найкращим варіантом є, мабуть, просто використання TextField замість CharField у вашій моделі. Ви також можете замінити formfield_for_dbfieldметод свого ModelAdminкласу:

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

чи є в цьому мінус порівняно з обраною відповіддю? це виглядає чистішим для реалізації, оскільки нам не потрібно створювати нову ModelForm ...
Філіпе Піна

3
замінити formfield.widget = forms.Textarea()з , formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)щоб зберегти всі атрибути автоматично згенерували для TextField, спасибі!
Філіпе Піна

2
Не знаю, чому приймається інша відповідь над цією; Я думаю, якщо все, що ви робите - це заміна віджету, це простіше. Але і те, і інше буде працювати нормально.
Carl Meyer

Це спрацювало чудово, дякую. Виклик супер () здається дещо багатослівним, чи існує простіший спосіб це зробити?
rjh

2
@rjh У py3 ви можете усунути все, що знаходиться всередині парен, і просто використовувати super(). Інакше ні.
Carl Meyer

32

У Ayaz є досить багато місця, крім невеликої зміни (?!):

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)

Отже, вам не потрібно перевизначати поле у ​​ModelForm, щоб змінити його віджет, просто встановіть dict віджетів у Meta.


1
Це зберігає більше "автоматичних" властивостей, ніж відповідь Ayaz, але будь-яка порада щодо того, як зберегти перевірку довжини поля?
Філіпе Піна

14

Ви можете підкласувати своє власне поле необхідним formfieldметодом:

class CharFieldWithTextarea(models.CharField):

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

Це вплине на всі згенеровані форми.


9

Вам не потрібно створювати клас форми самостійно:

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)

Див. ModelAdmin.get_form .


7

Якщо ви намагаєтеся змінити Textarea на admin.py, це рішення, яке мені вдалося:

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)

Якщо ви використовуєте базу даних MySQL, довжина стовпця зазвичай встановлюється автоматично до 250 символів, тому вам потрібно буде запустити ALTER TABLE, щоб змінити довжину бази даних MySQL, щоб ви могли скористатися новою більшою текстовою областю, яку ви є у вас сайт адміністратора Django.


6

Замість a models.CharFieldвикористовуйте models.TextFieldfor descr.


4
На жаль, max_length = повністю ігнорується Django у TextField, тому, коли вам потрібна перевірка довжини поля (наприклад, надання дозволу секретарям вводити зведення подій), єдиним способом отримати це є використання CharField. Але CharField - це спосіб скоротити до 300 символів. Звідси і розчин аязу.
шейкер

3
Це невдала відповідь, оскільки вона змінює базу даних. Сенс зміни віджету полягає у зміні способу відображення поля, а не в зміні схеми бази даних

1
Це чудова відповідь для когось (як я), який вчиться користуватися Django і, якби я знав про це, спочатку створив би базу даних по-іншому.
Ендрю Свіфт,

5

Ви можете використовувати models.TextFieldдля цієї мети:

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

3
Це змінить структуру БД, тому будьте обережні
elad silver

3

Хотіли розширити відповідь Карла Мейєра, яка дотепер працює чудово.

Я завжди використовую TextFieldзамість CharField(з можливістю вибору чи без) і накладаю обмеження на кількість символів на UI / API, а не на рівні БД. Щоб зробити цю роботу динамічно:

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

У мене є назва моделі Postде title, slugі stateце TextFieldз і stateмає вибір. Визначення адміністратора виглядає так:

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

Думав, що інші, хто шукає відповіді, можуть знайти це корисним.


Це formfield_for_dbfieldзадокументовано?
x-yuri
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.