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

Answers:


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,看到我的回答如下。
卡尔·梅耶

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:
斯科尔

2
您不需要自己创建表单,可以重写get_formmethod。看我的回答
x-yuri

更好的方法是使用Meta类Meta:模型=消息小部件= {'文本':forms.Textarea(attrs = {'cols':80,'rows':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 ...
Filipe Pina

3
取代formfield.widget = forms.Textarea()formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)保持对文本字段自动生成的所有属性,谢谢!
Filipe Pina '02

2
我不知道为什么对这个答案可以接受另一个答案。我认为,如果您要做的只是更换小部件,这会更简单。但是任何一个都可以。
卡尔·梅耶

很好,谢谢。虽然super()调用似乎有点冗长,但是有一种更简单的方法吗?
rjh 2015年

2
@rjh在py3中,您可以消除括号内的所有内容,而只需使用即可super()。否则没有。
卡尔·梅耶

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中重新定义字段即可更改其窗口小部件,只需在Meta中设置窗口小部件字典即可。


1
与Ayaz的答案相比,这确实保留了更多的“自动”属性,但是关于如何保持字段长度验证的任何技巧?
Filipe Pina '02

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

如果您要更改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中的长度,以便可以利用新的较大Textarea在您的Admin Django网站中。


6

代替a models.CharField,使用models.TextFieldfor descr


4
不幸的是,Django在TextField上完全忽略了max_length =,因此,当您需要字段长度验证(例如让秘书输入事件摘要)时,唯一的获取方法是使用CharField。但是,使用CharField可以将300个字符输入其中。因此,ayaz解决方案。
shacker

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
这将改变数据库的结构,所以要
格外

3

想要扩展卡尔·迈耶(Carl Meyer)的答案,该答案在此之前一直有效。

我总是使用TextField代替CharField(选择或不选择),并在UI / API端而不是在DB级别施加字符限制。要使其动态工作:

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记录吗?
x-yuri
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.