将Django ModelChoiceField查询集限制为所选项

这是我一天苦苦挣扎的......

我有一个消息模型,其中 recipientsManyToManyFieldUser 模型 .

然后有一个用于撰写邮件的表单 . 由于有数千个用户,在表单中的多选小部件中显示选项并不方便,这是默认行为 . 相反,使用FcbkComplete jquery插件,我使收件人字段看起来像用户键入收件人的输入字段,并且它工作 .

但...

虽然在表单页面上不可见,但所有用户列表都会在选择字段中呈现到页面中,这是我不想要的原因 .

我尝试重写ModelChoiceField操作验证和查询集的行为,我使用了MultipleChoice小部件,等等 . 但是没有一个工作并且感觉很自然 .

那么,避免在客户端使用整个选项列表,但仍然能够针对查询集进行验证的(最佳)方法是什么?

回答(4)

2 years ago

你见过django-ajax-selects吗?当我遇到一个类似于你想要解决的问题的时候,我的心理抓包里面的东西......

2 years ago

我会尝试两种方式中的一种(两者都可能很糟糕!我真的只是在这里大声思考):

  • 将字段的查询集设置为空(queryset = Model.objects.none())并使jquery工具使用ajax视图来选择/搜索用户 . 使用clean_field函数手动验证用户是否有效 .

  • 这将是我的首选:编辑模板不循环遍历字段的查询集 - 所以html在select标签内有0个选项 . 也就是说,不使用form.as_p()方法或任何东西 .

我不确定的一件事是#2是否仍会打到数据库,拔出5k对象,而不是在html中显示它们 . 我认为不应该,但......根本不确定!

2 years ago

如果您不关心建议,并且可以使用该ID,Django Admin会为这些情况提供raw_id_field属性 .

您还可以创建一个小部件,它使用用户名而不是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')

2 years ago

我通过覆盖 forms.ModelMultipleChoiceField 的默认小部件来解决这个问题 . 新窗口小部件仅返回选定的字段,而不是整个选项列表:

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)
    ...