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 在运行时评估查询集