Django ModelChoiceField:过滤查询集并将默认值设置为对象

Posted

技术标签:

【中文标题】Django ModelChoiceField:过滤查询集并将默认值设置为对象【英文标题】:Django ModelChoiceField: filtering query set and setting default value as an object 【发布时间】: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 以外的其他东西?

谢谢。

【问题讨论】:

【参考方案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)问题)

【讨论】:

@JonProgrammer 在表单中? 我目前的解决方案是这里的那个,但我觉得这不是最有效的方法:***.com/questions/51512606/django-forms-queryset【参考方案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()。

【讨论】:

以上是关于Django ModelChoiceField:过滤查询集并将默认值设置为对象的主要内容,如果未能解决你的问题,请参考以下文章

表单 ModelChoiceField 查询集 + 额外选择字段 django 表单

Django - ModelChoiceField 查询集如何工作?

Django ModelChoiceField 的问题

Django:让 ModelChoiceField 在运行时评估查询集

Django 表单不使用 ModelChoiceField 保存 - ForeignKey

带有modelchoicefield的Django多个表单->查询太多