Django-Admin:作为 TextArea 的 CharField
Posted
技术标签:
【中文标题】Django-Admin:作为 TextArea 的 CharField【英文标题】:Django-Admin: CharField as TextArea 【发布时间】:2010-09-30 15:27:07 【问题描述】:我有
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”字段?
更新: 仅在管理界面中!
使用 ModelForm 的好主意。
【问题讨论】:
【参考方案1】:您必须创建一个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
admin.ModelAdmin
的 form
属性记录在 Django 官方文档中。这里是one place to look at。
【讨论】:
为了简单地替换表单小部件,您不必创建自己的整个表单。您可以在ModelAdmin
上覆盖 formfield_for_dbfield
,请参阅下面的答案。
这给了django.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited
从 Django 1.7 开始,您还需要在 class Meta:
下添加 fields = '__all__'
。
你不需要自己创建表单,你可以重写get_form
方法。见my answer。
beeter 方法是使用 Meta class Meta: model = Message widgets = 'text': forms.Textarea(attrs='cols': 80, 'rows': 20),
【参考方案2】:
对于这种情况,最好的选择可能只是在模型中使用 TextField 而不是 CharField。您还可以覆盖 ModelAdmin
类的 formfield_for_dbfield
方法:
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()
。否则没有。【参考方案3】:
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 中重新定义字段来更改其小部件,只需在 Meta 中设置小部件 dict。
【讨论】:
这确实保留了比 Ayaz 的答案更多的“自动”属性,但是关于如何保持字段长度验证的任何提示?【参考方案4】:您不需要自己创建表单类:
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。
【讨论】:
【参考方案5】:您可以使用所需的formfield
方法对自己的字段进行子类化:
class CharFieldWithTextarea(models.CharField):
def formfield(self, **kwargs):
kwargs.update("widget": forms.Textarea)
return super(CharFieldWithTextarea, self).formfield(**kwargs)
这将影响所有生成的表单。
【讨论】:
【参考方案6】:如果您尝试更改 admin.py 上的 Textarea,这是对我有用的解决方案:
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 DB,您的列长度通常会自动设置为 250 个字符,因此您需要运行 ALTER TABLE 来更改 MySQL DB 中的长度,以便您可以利用新的更大的您在 Admin Django 站点中拥有的 Textarea。
【讨论】:
【参考方案7】:使用models.TextField
代替models.CharField
,而不是descr
。
【讨论】:
不幸的是,max_length= 在 TextField 上被 Django 完全忽略,因此当您需要字段长度验证(例如让秘书输入事件摘要)时,获得它的唯一方法是使用 CharField。但是 CharField 是一种短于输入 300 个字符的方法。因此,ayaz 解决方案。 这不是一个好的答案,因为它会更改数据库。更改小部件的重点是更改字段的显示方式,而不是更改数据库架构 对于正在学习如何使用 Django 的人(比如我)来说,这是一个很好的答案,如果我更了解的话,一开始会以不同的方式设置数据库。【参考方案8】:您可以为此使用models.TextField
:
class Sample(models.Model):
field1 = models.CharField(max_length=128)
field2 = models.TextField(max_length=1024*2) # Will be rendered as textarea
【讨论】:
这会改变数据库结构,所以要小心【参考方案9】:想要扩展 Carl Meyer 的答案,该答案在此之前完美运行。
我总是使用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
s 和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
记录了吗?以上是关于Django-Admin:作为 TextArea 的 CharField的主要内容,如果未能解决你的问题,请参考以下文章
textarea允许将行作为内容传递(jquery)[重复]