添加Django的Q()对象并获得两个互斥的JOIN ON [英] ADDing Django's Q() objects and get two exclusive JOIN ONs

查看:120
本文介绍了添加Django的Q()对象并获得两个互斥的JOIN ON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是场景:

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

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

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

The problem now is, that I'm dynamically constructing rather complex queries based on Q()-objects. They end up like this:

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

可以(并自动)减少为:

which can (and automatically will) be reduced to:

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

问题现在是,这会导致如下所示的SQL:

The problem now is, that this results in a SQL like this:

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

导致我实际需要的东西:

resulting in what I would actually need:

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编辑.

I can't use the proposed solution though because all of it is gonna be OR'ed again.

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

I would have to be able to do something like:

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

推荐答案

经过进一步的修改后,我意识到:Django QuerySets可以进行OR编辑.

After fiddling some more I realized: Django QuerySets can be OR'ed.

因此,我的解决方案是现在创建类似这样的内容:

My solution therefore is now to create something like this:

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

现在,所有内部AND都使用过滤器进行连接,而最外部的OR则是直接在QuerySet上的布尔值|.

All the inner ANDs are now concatenated using filters, and the outer-most ORs are boolean | directly on the QuerySets.

注意! 由于内部子查询总是被完全评估(不再有限制20"),因此请求变得慢得多.
OR -ing QuerySets将导致多个条目-所以最后一个

Heads up! Requests get much slower due to inner subqueries always being completely evaluated (no more "limit 20")
and OR-ing QuerySets will result in multiple entries - so a final

(QuerySet | QuerySet | QuerySet).distinct()

通常是必需的.

这篇关于添加Django的Q()对象并获得两个互斥的JOIN ON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆