【发布时间】:2011-04-10 09:58:26
【问题描述】:
我想将 TextInput 小部件的类属性设置为表单中所有使用它的字段的一个值,而不必在 Meta 中将它们全部列出:widgets = {...。这可能吗?
谢谢。
【问题讨论】:
标签: django django-forms
我想将 TextInput 小部件的类属性设置为表单中所有使用它的字段的一个值,而不必在 Meta 中将它们全部列出:widgets = {...。这可能吗?
谢谢。
【问题讨论】:
标签: django django-forms
使用您的 CSS 类创建一个新小部件:
class PrettyWidget(forms.TextInput):
class Media:
css = {
'all': ('pretty.css',)
}
在您的表单中,在所有字段中使用您的新小部件:
class ContactForm(forms.Form):
subject = TextField(widget=PrettyWidget)
【讨论】:
我过去做过的一件事是创建一个 lambda 函数来返回我经常使用的字段:
from django import forms
fancy = lambda: forms.TextInput(attrs={'class': 'derp'})
class MyForm(forms.Form):
attr1 = fancy()
attr2 = fancy()
attr3 = fancy()
我不记得为什么我选择使用函数来处理我的情况,但我怀疑它与为每个表单字段创建单独的 forms.TextInput 对象实例有关......
【讨论】:
您可以使用以下内容:
def set_attrs_for_fields(fields, default_attrs):
for field_name in fields:
field = fields[field_name]
try:
default_widget_attr = default_attrs[field.widget.__class__]
field.widget.attrs = default_widget_attr
except KeyError:
pass
class DefaultAttrForm(forms.Form):
def __init__(self, *args, **kwargs):
super(DefaultAttrForm, self).__init__(*args, **kwargs)
set_attrs_for_fields(self.fields, self.get_default_attrs())
def get_default_attrs(self):
'''
Child class should overwrite this method and return dict with example format
{forms.TextInput: {'class': 'my_value'}}
where keys, are widget classes for which default attrs will be set.
'''
raise NotImplementedError()
class DefaultAttrModelForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DefaultAttrModelForm, self).__init__(*args, **kwargs)
set_attrs_for_fields(self.fields, self.get_default_attrs())
def get_default_attrs(self):
'''
Child class should overwrite this method and return dict with example format
{forms.TextInput: {'class': 'my_value'}}
where keys, are widget classes for which default attrs will be set.
'''
raise NotImplementedError()
现在,每次您想为某些小部件使用默认属性时,您只需创建继承自 DefaultAttrForm 或 DefaultAttrModelForm 的类并覆盖方法 get_default_attrs。普通 Django 表单示例:
class MyForm(DefaultAttrForm):
my_field1 = forms.CharField(widget=forms.TextInput())
my_field2 = forms.CharField(widget=forms.PasswordInput(attrs={'my_non_default': 'Non default'}))
def get_default_attrs(self):
# all fields with widget TextInput will have
# default attrs set to {'class': 'my_value'}
return {forms.TextInput: {'class': 'my_value'},
}
In [1]: form = MyForm()
In [2]: form.fields['my_field1'].widget.attrs
Out[2]: {'class': 'my_value'}
In [3]: form.fields['my_field2'].widget.attrs
Out[3]: {'my_non_default': 'Non default'}
对于模型表单,请使用以下内容:
class MyModelForm(DefaultAttrModelForm):
class Meta:
model = my_model
def get_default_attrs(self):
# all fields with widget TextInput will have
# default attrs set to {'class': 'my_value'}
return {forms.TextInput: {'class': 'my_value'},
}
In [1]: form = MyModelForm()
In [2]: form.fields['my_field1'].widget.attrs
Out[2]: {'class': 'my_value'}
In [3]: form.fields['my_field2'].widget.attrs
Out[3]: {'my_non_default': 'Non default'}
【讨论】:
您可以重写构造函数以修改所有 TextInput 小部件:
from django import forms
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
if field.widget.__class__ == forms.widgets.TextInput:
if 'class' in field.widget.attrs:
field.widget.attrs['class'] += ' my-class'
else:
field.widget.attrs.update({'class':'my-class'})
class Meta:
model = MyModel
你能用装饰器覆盖初始化吗?此外,在 attrs.update() 之前应该有一个 if 语句,因为我想设置一个默认值而不是覆盖可能已经存在的内容。 ——凯文
未经测试,但如果你经常使用它,我想你可以从 MyForm 继承。
【讨论】:
对于 ModelForm,我们可以使用它。
from django import forms
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
# change a widget attribute:
self.fields['user_permissions'].widget.attrs["size"] = 5
self.fields['user_permissions'].widget.attrs["class"] = 'form-control required'
class Meta:
model = User
【讨论】: