将Django ModelChoiceField queryset限制为选定项
这是我挣扎了一天的事情 我有一个消息模型,将Django ModelChoiceField queryset限制为选定项,django,django-forms,validation,manytomanyfield,Django,Django Forms,Validation,Manytomanyfield,这是我挣扎了一天的事情 我有一个消息模型,收件人是用户模型的ManyToManyField 然后是一个用于编写消息的表单。由于有成千上万的用户,在表单中显示多选小部件中的选项并不方便,这是默认行为。相反,使用FcbkComplete jquery插件,我将recipients字段设置为一个输入字段,用户在其中键入收件人,然后它就可以工作了 但是 虽然在表单页面上不可见,但所有用户列表都会呈现在选择字段的页面中,这是我不希望看到的,原因很明显 我试图覆盖ModelChoiceField的行为操纵验
收件人
是用户
模型的ManyToManyField
然后是一个用于编写消息的表单。由于有成千上万的用户,在表单中显示多选小部件中的选项并不方便,这是默认行为。相反,使用FcbkComplete jquery插件,我将recipients字段设置为一个输入字段,用户在其中键入收件人,然后它就可以工作了
但是
虽然在表单页面上不可见,但所有用户列表都会呈现在选择字段的页面中,这是我不希望看到的,原因很明显
我试图覆盖ModelChoiceField的行为操纵验证和queryset,我玩MultipleEchoice小部件,等等。但它们都不起作用,感觉也不自然
那么,什么(最好的)方法可以避免在客户端拥有完整的选项列表,但仍然能够根据查询集进行验证呢?您看到了吗?我从来没有用过它,但它就在我的脑子里,当我遇到一个问题,比如你想解决的问题时…我会尝试两种方法中的一种(这两种方法都可能不好!我只是在这里大声思考):
有一件事我不确定,那就是#2是否仍然会命中数据库,拉出5k+对象,只是不在html中显示它们。我认为不应该,但是。。。一点也不确定 如果您不关心建议,并且可以使用ID,Django Admin会为这些情况提供一个属性 您还可以制作一个小部件,它使用用户名而不是ID,并返回一个有效的用户。以下几行中的某一行:
# I haven't tested this code. It's just for illustration purposes
class RawUsernameField(forms.CharField):
def clean(self, value):
try:
return User.objects.get(username=value)
except User.DoesNotExist:
rause forms.ValidationError(u'Invalid Username')
我通过覆盖
forms.modelmultipleechoicefield
的默认小部件来解决这个问题。新窗口小部件仅返回所选字段,而不是整个选项列表:
class SelectMultipleUserWidget(forms.SelectMultiple):
def render_options(self, choices, selected_choices):
choices = [c for c in self.choices if str(c[0]) in selected_choices]
self.choices = choices
return super(SelectMultipleUserWidget,
self).render_options([], selected_choices)
class ComposeForm(forms.Form):
recipients = forms.ModelMultipleChoiceField(queryset=User.objects.all(),
widget=SelectMultipleUserWidget)
...
对于1,在clean_字段()之前调用clean(),并引发
无效选项
异常。clean
也应该被覆盖,但它是一个选项。对于2,我不想弄乱模板,因为我有站点范围的字段和表单模板。但这也是一种选择。我仍然觉得应该有一种更干净、不那么刻薄、更像djangoish的方式。谢谢。您的问题的唯一可能的解决方案(假设queryset过滤器不够)是必须使用javascript和ajax视图。在我看来,这已经有相当多的漏洞了——你只能期望django是自一致的,它不能满足使用javascript的所有可能性。我想在调用super()之前,我应该重写clean()方法使其工作:/mmm hacky!另一个选项是将字段更改为CharField,使页面上的javascript返回逗号分隔的用户ID字符串-验证/清理没有问题,并重写save()以执行m2m保存。使用CharField会导致fcbkcomplete出现问题,因为它需要一个select字段。我可以使用其他内容来代替fcbkcomplete,但由于我需要显示用户名并发布用户id,使用select字段似乎更为自然。我仍然希望有一个干净干净利落的方法:/@user608133:从模板中删除选项并不能避免对数据库造成影响,因为表单字段在queryset上执行list(),从而强制对查询进行求值。此表单是为最终用户提供的,因此原始\u id\u字段不合适。对于第二种方法,自定义字段应该继承自ChoiceField,因为我需要将用户id和名称保留为select widget options的键和值对,因为名称会显示,id会发布。但对于ChoiceField,应该在初始化期间定义一个查询集,并导致其他问题,这些问题可以通过黑客的方式避免。非常感谢。