【问题标题】:Django ModelChoiceField: filtering query set and setting default value as an objectDjango ModelChoiceField:过滤查询集并将默认值设置为对象
【发布时间】:2011-07-16 19:41:36
【问题描述】:

我在Models 中定义了一个 Django Form 类:

class AccountDetailsForm(forms.Form):
    ...
    adminuser = forms.ModelChoiceField(queryset=User.objects.all())

这工作正常,但它有一些我似乎无法解决的限制:

(1) 我想在查询集上使用过滤器,基于传递给表单的变量accountid,如下所示:

User.objects.filter(account=accountid)

这在模型中不起作用,因为accountid 当然不能作为变量传递。

因此queryset 必须以某种方式在Views 中定义,但据我所知,它是Form 类中的必填字段。

(2) 我想在数据库中默认选择AccountDetailsForm 一个对象,我可以像这样在Views 中选择:

User.objects.filter(account=accountid).filter(primary_user=1)

我尝试将 adminuser 指定为表单中的默认值,(适用于其他标准表单字段,例如 CharField):

adminuser = User.objects.filter(account=accountid).filter(primary_user=1)

...

form = AccountDetailsForm({'adminuser': adminuser})
return render_to_response('accounts/edit/accountdetails.html', 
{'form': form, 'account':account})

但没有运气。

考虑到我在这里需要的灵活性,我是否应该使用 ModelChoiceField 以外的其他东西?

谢谢。

【问题讨论】:

    标签: django django-forms


    【解决方案1】:

    重写 init 方法并接受新的关键字参数

    class AccountDetailsForm(forms.Form):
        ...
        adminuser = forms.ModelChoiceField(queryset=User.objects.all())
        def __init__(self, *args, **kwargs):
            accountid = kwargs.pop('accountid', None)
            super(AccountDetailsForm, self).__init__(*args, **kwargs)
    
            if accountid:
                self.fields['adminuser'].queryset = User.objects.filter(account=accountid)
    
    form = AccountDetailsForm(accountid=3)
    

    您也可以随时在视图中手动设置选项。

    form = AccountDetailsForm()
    form.fields['adminuser'].queryset = User.objects.filter(account=accountid)
    

    请注意:您不是通过将字典传递给示例中的表单来设置默认值。

    您实际上是在创建一个绑定表单,可能会触发验证和所有这些爵士乐。

    要设置默认值,use the initials argument.

    form = AccountDetailsForm(initial={'adminuser':'3'})
    

    【讨论】:

    • 您好,感谢您的回复。在视图中设置查询集效果很好。我无法解决的部分是将 ModelChoiceField 的绑定表单值(而不是默认值)设置为 User.objects.filter(account=accountid).filter(primary_user=1)。谢谢。
    【解决方案2】:

    您可以覆盖视图中的字段

    yourForm = AccountDetailsForm()
    
    yourForm.fields['accomodation'] = forms.ModelChoiceField(User.objects.filter(account=accountid).filter(primary_user=1))
    

    【讨论】:

      【解决方案3】:

      在 Django 2.0 中,您可以像这样将对象(在您的情况下为 User)从 view 传递到 form(您必须先从数据库中检索 obj):

      form = AccountDetailsForm(initial={'adminuser': adminuser})
      

      它会给你一个默认选择的对象(回答你的 2)问题)

      【讨论】:

      【解决方案4】:

      这里还没有提到Form.clean() 方法。此方法专门用于自定义验证。

      对于您的示例,您可以执行以下操作:

      class AccountDetailsForm(forms.Form):
          adminuser = forms.ModelChoiceField(queryset=User.objects.all())
          account_id = forms.IntegerField()  # or ModelChoiceField if that applies
      
          def clean(self):
              account_id = self.cleaned_data['account_id']
              self.cleaned_data['adminuser'] = User.objects.filter(account_id=account_id)
      
          return self.cleaned_data
      

      clean() 方法在默认的 clean 方法之后调用,因此您可以使用 self.cleaned_data(与视图中的 form.cleaned_data 相同)并根据需要返回它。

      更好的是,您可以根据要清理的字段 (def clean_adminuser) 为方法命名,并使其更易于阅读。

      def clean_adminuser(self):
          account_id = self.cleaned_data['account_id']
          return User.objects.filter(account_id=account_id)
      

      如果有任何问题要处理,也可以在此方法中致电Form.add_error()

      【讨论】:

        猜你喜欢
        • 2013-03-14
        • 1970-01-01
        • 1970-01-01
        • 2016-06-24
        • 2018-09-02
        • 2014-11-15
        • 1970-01-01
        • 2014-01-08
        • 2014-01-16
        相关资源
        最近更新 更多