Django:使用原始查询来限制 ModelForm 中的外键选择字段

Posted

技术标签:

【中文标题】Django:使用原始查询来限制 ModelForm 中的外键选择字段【英文标题】:Django: Using a raw query to limit a foreignkey choicefield in a ModelForm 【发布时间】:2012-08-12 22:54:52 【问题描述】:

以经典的 foo bar 为例:

models.py:

Class Foo(models.Model):
    name = models.CharField(max_length= 200)

Class Bar(models.Model):
    name = models.CharField(max_length= 200)
    foo = models.ForeignKey('Foo')

在我的表单中,我尝试使用原始查询将foreignkeyFoo 的选择限制为Foo 的子集。

forms.py:

class BarForm(ModelForm):
    search_field = CharField(max_length=100, required=False)

    def __init__(self,*args,**kwargs):
        search_str = kwargs.pop('search_str', None)
        super(BarForm,self ).__init__(*args,**kwargs)
        self.fields['search_field'].initial = search_str
        self.fields['foo'].queryset = Bar.objects.raw("""
select f.id as id, f.name as name from bar_lookup(%s)""", [search_str])

    class Meta:
        model = Bar
        exclude = ('foo',)

bar_lookup(%s) 是一个返回表的 DB 过程。它搜索多个关系并以优化的方式处理结果的过滤和排序。它可以工作,我宁愿不必在 Django 代码中再次对其进行编码。

我收到以下错误:"'RawQuerySet' object has no attribute 'all'"。 如果我改用普通的Bar.objects.filter(),则该表单有效。

我应该如何将我的RawQuerySet 转换为普通的QuerySet? 我应该使用self.fields['line_stop'].choice 选项吗?

【问题讨论】:

哪一行引发了异常?尝试迭代列表时是否有异常? 问题行是 :self.fields['foo'].queryset = Bar.objects.raw(""" select f.id as id, f.name as name from bar_lookup(%s )""", [search_str]) 你能告诉我模板中的行吗? 我只是使用模板标签 MyBar.foo 不清楚 MyBar 是什么。你能说明你是如何创建变量的吗? 【参考方案1】:

我遇到了类似的问题,并提出了这个棘手的解决方案:

class BarForm(ModelForm):
    search_field = CharField(max_length=100, required=False)

    def __init__(self,*args,**kwargs):
        search_str = kwargs.pop('search_str', None)
        super(BarForm,self ).__init__(*args,**kwargs)
        self.fields['search_field'].initial = search_str
        self.foo_choices = Bar.objects.raw("""
              select f.id as id, f.name as name from bar_lookup(%s)""", [search_str])
        self.fields['foo'].choices = [(x.id, x) for x in self.foo_choices]

    def clean_foo(self):
        foo = self.cleaned_data['foo']
        if foo not in self.foo_choices:
             raise forms.ValidationError("Some error!")
        return foo

    class Meta:
        model = Bar

我知道它并不完美,子类化 ModelChoiceField 会更好。

【讨论】:

以上是关于Django:使用原始查询来限制 ModelForm 中的外键选择字段的主要内容,如果未能解决你的问题,请参考以下文章

[Django] 查看orm自己主动运行的原始查询sql

Django prefetch_related 与限制

Django - 使用原始查询并通过参数排序

Django:分页器 + 原始 SQL 查询

Django QuerySet 与原始查询性能

Django 视图中的原始 SQL 查询