【问题标题】:How to load a form with options from a queryset in Django如何在 Django 中使用查询集中的选项加载表单
【发布时间】:2019-12-02 20:14:14
【问题描述】:

我正在尝试加载带有用户付款选项的表单,因此需要从用户个人资料中设置查询。

我已尝试在需要用户的情况下初始化表单(如下代码)。问题是如果我在初始化时制作 self.options 。我也尝试过创建choice_field

class ListPaymentOptionsForm(forms.Form):

    choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=options)

    def __init__(self, user, *args, **kwargs):
        self.options = list(UserPaymentOption.objects
                                               .values_list('last_four', 'last_four')
                                               .filter(user=user, active=True))
        super(ListPaymentOptionsForm, self).__init__(self, *args, **kwargs)

上面的代码给出了这个错误: 选择字段 = forms.ChoiceField(小部件=forms.RadioSelect,选择=选项) NameError: name 'options' 没有定义

然后我尝试像这样在视图上添加选项

form = ListPaymentOptionsForm(user=request.user)
form.fields['choice_field'].choices = list(UserPaymentOption.objects
                                               .values_list('id', 'last_four')
                                               .filter(user=request.user, active=True))

这会导致在发布时使用的表单出现错误,这似乎是因为它试图验证提供的值是一个选项,但在实际表单中该选项未设置。我认为这是问题的原因是这就是表单返回的内容

form=ListPaymentOptionsForm(request.POST)
print(form)

这将返回:选择字段:

  • 选择一个有效的选项。 54 不是可用的选择之一。
  • 对此的任何意见将不胜感激。谢谢。

    【问题讨论】:

      标签: django forms radio-button


      【解决方案1】:

      快到了!

      尝试在构造函数中执行fields['choice_field'].choices

      class ListPaymentOptionsForm(forms.Form):
          def __init__(self, user, *args, **kwargs):
          super().__init__(*args, **kwargs) # assuming python 3 constructor
          self.options = list(UserPaymentOption.objects.values_list('last_four', 'last_four').filter(user=user, active=True))
          self.fields['choice_field'] = forms.ChoiceField(widget=forms.RadioSelect, choices=self.options)
      

      也许可以考虑看看ModelChoiceField,但是这样你就可以指定一个查询集,而不必担心创建一个list

      class ListPaymentOptionsForm(forms.Form):
              choice_field = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=UserPaymentOption.objects.none())
      
          def __init__(self, user, *args, **kwargs):
              super().__init__(*args, **kwargs)
              self.fields['choice_field'].queryset = UserPaymentOption.objects.filter(user=user, active=True)
      

      基于 cmets 进行编辑,我们可以使用 kwargs 传递用户,这可能会更好:

      class ListPaymentOptionsForm(forms.Form):
              choice_field = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=UserPaymentOption.objects.none())
      
          def __init__(self, *args, **kwargs):
              user = kwargs.pop('user') # this must be done before super()
              super().__init__(*args, **kwargs)
              self.fields['choice_field'].queryset = UserPaymentOption.objects.filter(user=user, active=True)
      

      然后实例化表单来处理 POST 数据: form = ListPaymentOptionsForm(request.POST, user=user)

      【讨论】:

      • 谢谢!我真的很喜欢你展示的 ModelChoiceField 选项。他们两个选项都使用查询集加载单选按钮,但是当我尝试发布时,我目前只有form = ListPaymentOptionsForm(request.POST) 并且收到此错误:int() 参数必须是字符串、字节类对象或数字,而不是 '查询字典'。有什么想法会导致这种情况吗?
      • @BrentLageson 我们将User 实例传递给表单的构造函数,因此在使用 POST 数据实例化表单时需要传入它。试试:form = ListPaymentOptionsForm(user, request.POST)
      • 我也有类似的想法,但是当我通过用户时,它说给出了用户的两个实例。这很奇怪,因为当我创建表单而不是帖子时,我使用了form = ListPaymentOptionsForm(request.user),并且按预期工作。 (再次感谢您的反馈)
      • 好的,我会更新我的答案,做一些应该有帮助的更改
      • 做到了!再次感谢您,我尝试为您投票,但显然我的声誉仍然很低。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 2013-04-05
      • 2021-11-27
      • 1970-01-01
      • 2022-11-12
      • 2018-06-01
      相关资源
      最近更新 更多