从视图中,如何将自定义“选择”传递到表单的 ChoiceField?

Posted

技术标签:

【中文标题】从视图中,如何将自定义“选择”传递到表单的 ChoiceField?【英文标题】:From the View, how do I pass custom "choices" into a form's ChoiceField? 【发布时间】:2018-05-01 23:17:57 【问题描述】:

根据 Django 文档,ChoiceField 接受 an iterable of two tuples, "or a callable that returns such an iterable" 用作字段的选择。

我在表单中定义了ChoiceFields

class PairRequestForm(forms.Form):
    favorite_choices = forms.ChoiceField(choices=[], widget=Radioselect, required=False)

这是我试图传递自定义选择元组的视图:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_initial(self):
        requester_obj = Profile.objects.get(user__username=self.request.user)
        accepter_obj = Profile.objects.get(user__username=self.kwargs.get("username"))

        # `get_favorites()` is the object's method which returns a tuple.
        favorites_set = requester_obj.get_favorites()

        initial = super(PairRequestView, self).get_initial()

        initial['favorite_choices'] = favorites_set

        return initial

在我的models.py 中,这是上面使用的返回元组的方法:

def get_favorites(self):
        return (('a', self.fave1), ('b', self.fave2), ('c', self.fave3))

据我了解,如果我想预先填充表单,我会通过覆盖get_initial() 来传递数据。我尝试使用可调用设置表单favorite_choices 的初始数据。可调用的是favorites_set

使用当前代码,我得到一个错误'tuple' object is not callable

如何使用自己的选择预先填充 RadioSelect ChoiceField?

编辑:我也试过设置initial['favorite_choices'].choices = favorites_set

【问题讨论】:

【参考方案1】:

get_initial 方法用于填充表单字段的初始值。不要设置可用的choices 或修改你的字段属性。

要成功地将您的选择从视图传递到表单,您需要在视图中实现get_form_kwargs 方法:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_form_kwargs(self):
        """Passing the `choices` from your view to the form __init__ method"""

        kwargs = super().get_form_kwargs()

        # Here you can pass additional kwargs arguments to the form.
        kwargs['favorite_choices'] = [('choice_value', 'choice_label')]

        return kwargs

在您的表单中,从 __init__ 方法中的 kwargs 参数中获取选项并在字段中设置选项:

class PairRequestForm(forms.Form):

    favorite_choices = forms.ChoiceField(choices=[], widget=RadioSelect, required=False)

    def __init__(self, *args, **kwargs):
        """Populating the choices of  the favorite_choices field using the favorites_choices kwargs"""

        favorites_choices = kwargs.pop('favorite_choices')

        super().__init__(*args, **kwargs)

        self.fields['favorite_choices'].choices = favorites_choices

瞧!

【讨论】:

在编辑self.fields[].choices 之前调用super().__init__() 是否有特殊原因? 如果您之前不调用基本__init__,您将不会定义任何fields 属性。 fields 属性在此处的BaseForm init 方法中定义:github.com/django/django/blob/master/django/forms/forms.py#L95【参考方案2】:

另一种简单的方法是:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_form(self, *args, **kwargs):
         requester_obj = Profile.objects.get(user__username=self.request.user)
         favorites_set = requester_obj.get_favorites()
         form = super().get_form(*args, **kwargs)
         form.fields['favorite_choices'].choices = favorites_set
         return form

【讨论】:

【参考方案3】:

您应该将选择封装在表单构造函数的适当参数中。假设您有一个“组”下拉菜单,并且您想传递“组选择”:

class CreateAccountForm(forms.Form):

   def __init__(self, groupChoices_, *args, **kwargs):
      super(CreateAccountForm, self).__init__(*args, **kwargs)
      self.fields['group'].choices = groupChoices_

   group = forms.ChoiceField()

在您看来,始终使用 groupChoices_ 作为第一个参数,例如:

groupChoices = [
  (2, 'A'),
  (4, 'B'),
]
form = CreateAccountForm(groupChoices, request_.POST)

不用担心kwargs太可怕了!

【讨论】:

这不能回答问题,因为 OP 使用 FormView

以上是关于从视图中,如何将自定义“选择”传递到表单的 ChoiceField?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 drupal 6 中的自定义字段将自定义版本的节点/添加表单放在视图中?

将自定义单元格从一个视图控制器传递到另一个视图控制器

如何将自定义字段添加到 WooCommerce 注册表单

将自定义道具传递给 TypeScript 中的 Redux 表单字段

如何将自定义信息从 App Engine Authenticator 传递到 Endpoint?

如何将自定义字段添加到 devise_invitable 邀请表单