在Django Admin中调整字段大小


107

Django倾向于在管理员上添加或编辑条目时填充水平空间,但是在某些情况下,这是真正的空间浪费,例如,编辑日期字段(8个字符宽)或CharField(也可以是6或8)字符宽,然后编辑框最多为15或20个字符。

如何告诉管理员文本框的宽度或TextField编辑框的高度?


9
显然,在这种情况下,您忘记这样做了。两年多以后。=)
casperOne 2012年

项目被抛弃了,我有一阵子没看到代码了。我可能在下个月开始一个新项目,所以也许我会再讲一次:D
Andor 2012年

Answers:


209

您应该使用ModelAdmin.formfield_overrides

这很容易- admin.py定义:

from django.forms import TextInput, Textarea
from django.db import models

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {'widget': TextInput(attrs={'size':'20'})},
        models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':40})},
    }

admin.site.register(YourModel, YourModelAdmin)

1
这正是我一直在寻找的内容,而无需进行一些荒谬的模板自定义。谢谢!
克里斯

2
请注意,如果为YourModelAdmin中的相应字段设置了filter_horizontal或,则此方法将filter_vertical无效。我花了一些时间来解决这个问题。
丹尼斯·哥洛马佐夫

有任何形式的求助对象吗?我找不到为所有Textareas设置attrs属性的方法。
朱利安

1
我只用过,models.TextField: {'widget': Textarea(attrs={'rows':4})}但是宽度也变小了。
史密斯·约翰斯

显然很难让它们具有相同的大小。
瑟伦

44

您可以使用其“ attrs”属性在窗口小部件上设置任意HTML属性。

您可以在Django管理员中使用formfield_for_dbfield进行此操作:

class MyModelAdmin(admin.ModelAdmin):
  def formfield_for_dbfield(self, db_field, **kwargs):
    field = super(ContentAdmin, self).formfield_for_dbfield(db_field, **kwargs)
    if db_field.name == 'somefield':
      field.widget.attrs['class'] = 'someclass ' + field.widget.attrs.get('class', '')
    return field

或带有自定义Widget子类和formfield_overrides字典

class DifferentlySizedTextarea(forms.Textarea):
  def __init__(self, *args, **kwargs):
    attrs = kwargs.setdefault('attrs', {})
    attrs.setdefault('cols', 80)
    attrs.setdefault('rows', 5)
    super(DifferentlySizedTextarea, self).__init__(*args, **kwargs)

class MyModelAdmin(admin.ModelAdmin):
  formfield_overrides = { models.TextField: {'widget': DifferentlySizedTextarea}}

29

更改特定字段的宽度。

通过ModelAdmin.get_form制成

class YourModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(YourModelAdmin, self).get_form(request, obj, **kwargs)
        form.base_fields['myfield'].widget.attrs['style'] = 'width: 45em;'
        return form

我认为这是最好的答案,因为它允许更改各个字段而不必创建新的表单。
rbennell

20

一种快速而肮脏的选择是简单地为所讨论的模型提供自定义模板。

如果您创建一个名为的模板,admin/<app label>/<class name>/change_form.html则管理员将使用该模板代替默认模板。也就是说,如果您在名为Person的应用中有一个名为的模型people,则可以创建一个名为的模板admin/people/person/change_form.html

所有管理模板都有一个extrahead块,您可以覆盖该块以将内容放入中<head>,而难题的最后一部分是每个字段的HTML ID为id_<field-name>

因此,您可以在模板中添加以下内容:

{% extends "admin/change_form.html" %}

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}

谢谢!这和alanjds的答案对于按字段(而不是按字段类型)更改管理界面中的布局非常有用。
nealmcb

10

如果要更改每个字段实例的属性,可以将“ attrs”属性直接添加到表单条目中。

例如:

class BlogPostForm(forms.ModelForm):
    title = forms.CharField(label='Title:', max_length=128)
    body = forms.CharField(label='Post:', max_length=2000, 
        widget=forms.Textarea(attrs={'rows':'5', 'cols': '5'}))

    class Meta:
        model = BlogPost
        fields = ('title', 'body')

“ attrs”属性基本上沿HTML标记传递,它将调整表单字段。每个条目都是您要覆盖的属性的元组,以及您要覆盖其的值。您可以输入任意多个属性,只要用逗号分隔每个元组即可。


IMO一次修改单个字段而不是一次修改所有TextInput小部件的最佳方法(就像公认的答案一样)
脚本作者

7

我发现最好的方法是这样的:

class NotificationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs): 
        super(NotificationForm, self).__init__(*args, **kwargs)
        self.fields['content'].widget.attrs['cols'] = 80
        self.fields['content'].widget.attrs['rows'] = 15
        self.fields['title'].widget.attrs['size'] = 50
    class Meta:
        model = Notification

对于ModelForm而言,它比使用不同的小部件覆盖字段要好得多,因为它可以保留namehelp_text属性以及模型字段的默认值,因此您不必将它们复制到表单中。


7

我在TextField中遇到了类似的问题。我正在使用Django 1.0.2,并且想要在关联的textarea中更改“行”的默认值。该版本不存在formfield_overrides。重写formfield_for_dbfield可以,但是我必须对每个ModelAdmin子类都这样做,否则会导致递归错误。最终,我发现将以下代码添加到models.py可以正常工作:

from django.forms import Textarea

class MyTextField(models.TextField):
#A more reasonably sized textarea                                                                                                            
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": Textarea(attrs={'rows':2, 'cols':80})}
         )
         return super(MyTextField, self).formfield(**kwargs)

然后在定义模型时使用MyTextField而不是TextField。我从这个答案中将其改编为类似的问题。


5

Django FAQ对此进行了很好的描述:

问:如何更改模型中字段上小部件的属性?

答:覆盖ModelAdmin / StackedInline / TabularInline类中的formfield_for_dbfield

class MyOtherModelInline(admin.StackedInline):
    model = MyOtherModel
    extra = 1

    def formfield_for_dbfield(self, db_field, **kwargs):
        # This method will turn all TextFields into giant TextFields
        if isinstance(db_field, models.TextField):
            return forms.CharField(widget=forms.Textarea(attrs={'cols': 130, 'rows':30, 'class': 'docx'}))
        return super(MyOtherModelInline, self).formfield_for_dbfield(db_field, **kwargs)

当我使用此技术时,帮助文本将不会出现,并且如果它是TabularInline,则列标题将变为“无”。
史蒂文·T·斯奈德,

1
这不是一个好方法,因为您要清除CharField中的所有其他设置。例如,默认情况下,它将智能地检测是否需要form字段,但是此代码将销毁它。您应该改为在您的super()调用返回的值上设置小部件。
塞林2012年

5

您总是可以在自定义样式表中设置字段大小,并告诉Django将其用于ModelAdmin类:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}

最佳答案!无需摆弄formfields和属性(以及可能的副作用),只需一个css文件,该文件可以使用django admin表单中的现有标识/类轻松地仅定位某些甚至所有字段。大起来!
benzkji

2

对于1.6,使用表格我必须在charfield内指定textarea的属性:

test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])

1

与msdin的答案相同,但使用TextInput而不是TextArea:

from django.forms import TextInput

class ShortTextField(models.TextField):
    def formfield(self, **kwargs):
         kwargs.update(
            {"widget": TextInput(attrs={'size': 10})}
         )
         return super(ShortTextField, self).formfield(**kwargs)

1

这是一个简单但灵活的解决方案。使用自定义表单覆盖某些小部件。

# models.py
class Elephant(models.Model):
    name = models.CharField(max_length=25)
    age = models.IntegerField()

# forms.py
class ElephantForm(forms.ModelForm):

    class Meta:
        widgets = {
            'age': forms.TextInput(attrs={'size': 3}),
        }

# admin.py
@admin.register(Elephant)
class ElephantAdmin(admin.ModelAdmin):
    form = ElephantForm

中提供的小部件 ElephantForm将替换默认的。关键是字段的字符串表示形式。表单中未指定的字段将使用默认窗口小部件。

请注意,尽管age是,但IntegerField我们可以使用该TextInput小部件,因为与不同NumberInput,它TextInput接受size属性。

本文介绍此解决方案。


0

如果您正在使用涉及选项/选项/下拉菜单的ForeignKey字段,则可以formfield_for_foreignkey在Admin实例中覆盖:

class YourNewAdmin(admin.ModelAdmin):
    ...

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'your_fk_field':
            """ For your FK field of choice, override the dropdown style """
            kwargs["widget"] = django.forms.widgets.Select(attrs={
                'style': 'width: 250px;'
            })

        return super().formfield_for_foreignkey(db_field, request, **kwargs)

这种模式的更多信息,在这里这里


-1

还有另一个例子:

class SecenekInline(admin.TabularInline):
   model = Secenek
   # classes = ['collapse']
   def formfield_for_dbfield(self, db_field, **kwargs):
       field = super(SecenekInline, self).formfield_for_dbfield(db_field, **kwargs)
       if db_field.name == 'harf':
           field.widget = TextInput(attrs={'size':2})
       return field
   formfield_overrides = {
       models.TextField: {'widget': Textarea(attrs={'rows':2})},
   }
   extra = 2

如果只想编辑特定的字段大小,则可以使用它。

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.