添加Django的Q()对象并获得两个独占的JOIN ON

时间:2015-05-23 22:24:47

标签: django django-queryset django-q

所以这就是场景:

class Person(models.Model):
    ...
class Aktion(models.Model):
    ...

class Aktionsteilnahme(models.Model):
    person = models.ForeignKey(Person)
    aktion = models.ForeignKey(Aktion)

现在的问题是,我基于Q() - 对象动态构建相当复杂的查询。他们最终是这样的:

Person.objects.filter(
    Q((Q()|Q(aktionsteilnahme__aktion=302))&
    (Q()|Q(aktionsteilnahme__aktion=547)))
)

可以(并自动将)缩减为:

Person.objects.filter(
    Q(aktionsteilnahme__aktion=302)&
    Q(aktionsteilnahme__aktion=547)
)

问题现在是,这会导致像这样的SQL:

SELECT * FROM person
LEFT OUTER JOIN aktionsteilnahme ON ( person.id = aktionsteilnahme.person_id )
WHERE (aktionsteilnahme.aktion = 2890 AND aktionsteilnahme.aktion = 5924)

但实际上我需要的是:

Person.objects.filter(Q(aktionsteilnahme__aktion=302))
    .filter(Q(aktionsteilnahme__aktion=547))

导致我实际需要的东西:

SELECT * FROM person
INNER JOIN aktionsteilnahme ON ( person.id = aktionsteilnahme.person_id )
INNER JOIN aktionsteilnahme T4 ON ( person.id = T4.person_id )
WHERE (aktionsteilnahme.aktion = 302 AND T4.aktion = 547)

我无法使用建议的解决方案,因为所有这些都将再次OR

我必须能够做类似的事情:

Person.objects.filter(
    Q(
      Q(aktionsteilnahme__aktion=302))
      .filter(Q(aktionsteilnahme__aktion=547))
    )
    |
    Q(other_q_filters)
)

1 个答案:

答案 0 :(得分:2)

在摆弄了一些之后,我意识到:Django QuerySets可以是OR&#39}。

我的解决方案现在是创建这样的东西:

Person.objects.filter(Q(aktionsteilnahme__aktion=302))
      .filter(Q(aktionsteilnahme__aktion=547))
|
Person.objects.filter(Q(other_q_filters))

现在所有内部AND都使用过滤器进行连接,而最外层的OR直接在QuerySet上布局为|

抬头! 请求慢得多,因为内部子查询总是被完全评估(不再是"限制20&#34 )
OR - QuerySets将导致多个条目 - 所以最终

(QuerySet | QuerySet | QuerySet).distinct()

通常是必要的。