【问题标题】:Why Does Specifying choices to a Widget not work in ModelForm.__init__为什么在 ModelForm.__init__ 中为 Widget 指定选项不起作用
【发布时间】:2010-08-07 20:27:03
【问题描述】:

如果我在 Django 中覆盖 ModelForm 的字段,我试图理解为什么我不能为表单字段的小部件指定选项。如果我给字段选择而不是小部件,它会起作用。我的理解是/是,如果您为字段提供选择,它将被传递到小部件进行渲染。我知道我可以让它与下面的前三个 sn-ps 中的任何一个一起工作,但我只是想完全理解为什么这种方法不起作用。

这是我的 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)
                )

【问题讨论】:

    标签: python django django-forms


    【解决方案1】:

    我认为最好的解释方式是遍历 the codeChoiceFieldTypeChoiceField 的超类。

    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)
                )
    
    1. 小部件已初始化,使用choices=guest.Choices
    2. super(ChoiceField, self).__init__ 设置 self.widget=widget。小部件的选项仍然设置。
    3. self.choices=choices 将字段小部件的选项设置为默认的(),因为它没有被指定(参见上面的_set_choices)。

    希望这是有道理的。查看代码还可以解释为什么您的其他示例有效。要么同时为小部件和选择字段设置选项,要么在初始化选择字段后设置小部件的选项。

    【讨论】:

    • 哦,对了,我和你在一起。它被覆盖,因为未指定字段的选择。谢谢!
    猜你喜欢
    • 2021-07-24
    • 2019-10-25
    • 1970-01-01
    • 2018-09-07
    • 2015-02-18
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2021-04-30
    相关资源
    最近更新 更多