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.ModelAdminform 属性记录在 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,其中titleslugstateTextFields 和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的主要内容,如果未能解决你的问题,请参考以下文章

如何测试自定义 django-admin 命令

在 django-admin 中更新记录的问题

如何将textarea值作为单独的变量?

textarea允许将行作为内容传递(jquery)[重复]

Angular Material matDatepicker 和 Textarea 作为表单的一部分

将 \n 作为 <br> 从 textarea 保存到数据库 [重复]