Django倾向于在管理员上添加或编辑条目时填充水平空间,但是在某些情况下,这是真正的空间浪费,例如,编辑日期字段(8个字符宽)或CharField(也可以是6或8)字符宽,然后编辑框最多为15或20个字符。
如何告诉管理员文本框的宽度或TextField编辑框的高度?
Django倾向于在管理员上添加或编辑条目时填充水平空间,但是在某些情况下,这是真正的空间浪费,例如,编辑日期字段(8个字符宽)或CharField(也可以是6或8)字符宽,然后编辑框最多为15或20个字符。
如何告诉管理员文本框的宽度或TextField编辑框的高度?
Answers:
您应该使用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)
filter_horizontal
或,则此方法将filter_vertical
无效。我花了一些时间来解决这个问题。
models.TextField: {'widget': Textarea(attrs={'rows':4})}
但是宽度也变小了。
您可以使用其“ 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}}
更改特定字段的宽度。
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
一种快速而肮脏的选择是简单地为所讨论的模型提供自定义模板。
如果您创建一个名为的模板,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 %}
如果要更改每个字段实例的属性,可以将“ 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标记传递,它将调整表单字段。每个条目都是您要覆盖的属性的元组,以及您要覆盖其的值。您可以输入任意多个属性,只要用逗号分隔每个元组即可。
我发现最好的方法是这样的:
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而言,它比使用不同的小部件覆盖字段要好得多,因为它可以保留name
和help_text
属性以及模型字段的默认值,因此您不必将它们复制到表单中。
我在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。我从这个答案中将其改编为类似的问题。
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)
这是一个简单但灵活的解决方案。使用自定义表单覆盖某些小部件。
# 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
属性。
本文介绍了此解决方案。
如果您正在使用涉及选项/选项/下拉菜单的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)
还有另一个例子:
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
如果只想编辑特定的字段大小,则可以使用它。