ADDing Django's Q() objects and get two exclusive JOIN ONs

守給你的承諾、 提交于 2019-12-11 17:33:37

问题


So this is the scenario:

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

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

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

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)

What I would actually need however is:

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)

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

回答1:


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

All the inner ANDs are now concatenated using filters, and the outer-most ORs are boolean | directly on the 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()

will usually be necessary.



来源:https://stackoverflow.com/questions/30418162/adding-djangos-q-objects-and-get-two-exclusive-join-ons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!