у меня есть
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.





Вместо models.CharField используйте models.TextField для descr.
К сожалению, max_length = полностью игнорируется Django в TextField, поэтому, когда вам нужна проверка длины поля (например, разрешение секретарям вводить сводки событий), единственный способ получить это - использовать CharField. Но CharField - это способ сократить до 300 символов. Отсюда и решение аяз.
Это плохой ответ, потому что он меняет базу данных. Смысл изменения виджета - изменить способ отображения поля, а не схему базы данных.
Это отличный ответ для кого-то (вроде меня), который учится использовать Django и, если бы я знал лучше, изначально настроил бы базу данных по-другому.
Вам нужно будет создать 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. Вот одно место, на которое можно посмотреть.
Для простой замены виджета формы вам не нужно создавать свою собственную форму целиком. Вы можете просто переопределить formfield_for_dbfield на вашем ModelAdmin, см. Мой ответ ниже.
Это дает django.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
Начиная с Django 1.7 вам необходимо добавить также fields = '__all__' под class Meta:.
Вам не нужно создавать форму самостоятельно, вы можете переопределить метод get_form. См. мой ответ.
Подход beeter заключается в использовании мета-класса Meta: model = Message widgets = {'text': forms.Textarea (attrs = {'cols': 80, 'rows': 20}),}
Вы можете создать подкласс своего собственного поля с помощью необходимого метода formfield:
class CharFieldWithTextarea(models.CharField):
def formfield(self, **kwargs):
kwargs.update({"widget": forms.Textarea})
return super(CharFieldWithTextarea, self).formfield(**kwargs)
Это повлияет на все сгенерированные формы.
В этом случае лучшим вариантом, вероятно, будет просто использовать 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 ...
заменил formfield.widget = forms.Textarea() на formfield.widget = forms.Textarea(attrs=formfield.widget.attrs), чтобы сохранить все атрибуты, автоматически сгенерированные для TextField, спасибо!
Я не знаю, почему принимается другой ответ вместо этого; Я думаю, что если все, что вы делаете, это заменяете виджет, это проще. Но и то, и другое будет работать нормально.
Это сработало отлично, спасибо. Вызов super () кажется немного многословным, есть ли более простой способ сделать это?
@rjh В py3 вы можете исключить все, что находится внутри скобок, и просто использовать super(). В противном случае нет.
@CarlMeyer: есть ли способ сохранить все атрибуты Charfield в текстовом поле, а также новые атрибуты, такие как столбцы и строки.
Вы также должны добавить: admin.site.register(Cab, CabAdmin) после определения класса
Документирован ли formfield_for_dbfield?
Использование TextField вместо CharField в модели является изменением на уровне базы данных и может иметь непредвиденные последствия. Есть причина, по которой это отдельные поля. Правильный способ сделать это - переопределить виджет.
Аяз в значительной степени прав, за исключением небольшого изменения (?!):
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.
Это сохраняет больше "автоматических" свойств, чем ответ Аяза, но есть ли подсказки о том, как сохранить проверку длины поля?
Если вы пытаетесь изменить 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, чтобы вы могли воспользоваться преимуществами нового большего Textarea, которое вы есть у вас админский сайт Django.
Хотел расширить ответ Карла Мейера, который отлично работает до сих пор.
Я всегда использую 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?
Для этого можно использовать models.TextField:
class Sample(models.Model):
field1 = models.CharField(max_length=128)
field2 = models.TextField(max_length=1024*2) # Will be rendered as textarea
Это изменит структуру БД, поэтому будьте осторожны.
Самостоятельно создавать класс формы не нужно:
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.
Принятый ответ - это огромный перебор с целью модификации только одного поля! ЛЮДИ ПОСЛЕДУЮТ ЭТОМ ОТВЕТУ Карла Мейера ДЛЯ ПРОСТОТЫ: stackoverflow.com/questions/430592/…