问题
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 AND
s are now concatenated using filters, and the outer-most OR
s 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