Почему указание выбора для виджета не работает в ModelForm .__ init__ - PullRequest
2 голосов
/ 08 августа 2010

Я пытаюсь понять, почему я не могу указать варианты для виджета поля формы, если я переопределяю поле ModelForm в Django. Это работает, если я даю варианты выбора в поле, но не виджет. Насколько я понимаю, / было то, что если вы дадите выбор полю, оно будет передано в виджет для рендеринга. Я знаю, что могу заставить это работать с любым из первых трех фрагментов ниже, но я просто хотел полностью понять, почему этот один способ не работает.

Это мой код 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 голосов
/ 08 августа 2010

Я думаю, что лучший способ объяснить это пройти через код для 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)
            )
  1. Виджет инициализирован, с выбором = guest.Choices
  2. super(ChoiceField, self).__init__ устанавливает self.widget = виджет. Выбор виджета по-прежнему установлен.
  3. self.choices=choices устанавливает для поля и виджета значение по умолчанию (), поскольку оно не было указано (см. _set_choices выше).

Надеюсь, это имеет смысл. Глядя на код также объясняет, почему ваши другие примеры работают. Либо выбор устанавливается для виджета и поля выбора одновременно, либо выбор виджета устанавливается после инициализации поля выбора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...