为什么在ModelForm.__init__中指定Widget的choices无效
我想弄明白为什么在Django中,如果我重写一个ModelForm的字段,就不能给表单字段的小部件指定选项。如果我直接给字段指定选项是可以的,但给小部件指定就不行。我原本以为如果给字段指定了选项,这些选项会传递给小部件进行渲染。我知道在下面的前三个代码片段中我可以让它工作,但我只是想完全理解为什么这种方式不行。
这是我的ModelForm代码,谢谢!
from django import forms
from models import Guest
class RSVPForm(forms.ModelForm):
class Meta:
model = Guest
def __init__(self, *args, **kwargs):
"""
Override a form's field to change the widget
"""
super(RSVPForm, self).__init__(*args, **kwargs)
# This works
self.fields['attending_ceremony'].required = True
self.fields['attending_ceremony'].widget=forms.RadioSelect(choices=Guest.CHOICES)
# This works
self.fields['attending_ceremony'].required = True
self.fields['attending_ceremony'].widget=forms.RadioSelect()
self.fields['attending_ceremony'].choices=Guest.CHOICES
# This works
self.fields['attending_ceremony'] = forms.TypedChoiceField(
required=True,
widget=forms.RadioSelect,
choices=Guest.CHOICES
)
# This doesn't - the choices aren't set (it's an empty list)
self.fields['attending_ceremony'] = forms.TypedChoiceField(
required=True,
widget=forms.RadioSelect(choices=Guest.CHOICES)
)
1 个回答
2
我觉得最好的解释方式是通过查看这段代码,它是ChoiceField
的代码,而TypeChoiceField
是它的子类。
class ChoiceField(Field):
widget = Select
default_error_messages = {
'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'),
}
def __init__(self, choices=(), required=True, widget=None, label=None,
initial=None, help_text=None, *args, **kwargs):
super(ChoiceField, self).__init__(required=required, widget=widget, label=label,
initial=initial, help_text=help_text, *args, **kwargs)
self.choices = choices
def _get_choices(self):
return self._choices
def _set_choices(self, value):
# Setting choices also sets the choices on the widget.
# choices can be any iterable, but we call list() on it because
# it will be consumed more than once.
self._choices = self.widget.choices = list(value)
choices = property(_get_choices, _set_choices)
根据你的例子,
self.fields['attending_ceremony'] = forms.TypedChoiceField(
required=True,
widget=forms.RadioSelect(choices=Guest.CHOICES)
)
- 首先,初始化了一个小部件(widget),并设置了选项为guest.Choices。
super(ChoiceField, self).__init__
这行代码把小部件(widget)设置为当前的widget。小部件的选项依然被保留。self.choices=choices
这行代码把字段的选项和小部件的选项都设置为默认值()
,因为没有特别指定(可以参考上面的_set_choices
)。
希望这样解释能让你明白。查看这段代码也能解释为什么你其他的例子能正常工作。要么是在初始化的时候同时为小部件和选择字段设置选项,要么是在选择字段初始化后再为小部件设置选项。