Reputation: 13
Calendars have a owner and have a ManyToMany
field 'assistants'
i have a Calendar who has 2 assistants one of which is its owner.
I think these 3 lines of code in the django shell can explain the weird behaviour quite well.
In [17]: Calendar.objects.filter(assistants=customer).exclude(owner=customer)
Out[17]: <QuerySet []>
In [20]: Calendar.objects.filter(owner=customer)
Out[20]: <QuerySet [<Calendar: aliz cal>, <Calendar: yassi has a calendar>]>
In [19]: Calendar.objects.filter(owner=customer) | Calendar.objects.filter(assistants=customer).exclude(owner=customer)
Out[19]: <QuerySet [<Calendar: aliz cal>, <Calendar: aliz cal>, <Calendar: yassi has a calendar>]>
Of course expected the result of queryset join to be the actual union of them.
Upvotes: 1
Views: 46
Reputation: 2921
Assuming this is for django 1.11+:
|
does not represent a union. It represents an OR-combination (which maintains all joins; hence aliz showing up twice) of two querysets .
qs1.filter(x=1) | qs2.exclude(x=1)
translates to:
SELECT STUFF FROM TABLES_AND_JOINS WHERE (x = 1 OR NOT (x = 1))
While qs1.filter(x=1).union(qs2.exclude(x=1))
translates to:
SELECT STUFF FROM TABLE1 WHERE x = 1 UNION SELECT STUFF FROM TABLE2 WHERE NOT x = 1
Use str(qs.query)
to see the SQL.
Upvotes: 1
Reputation: 5740
What you are doing is OR
-ing the WHERE
clauses of both queries, which is different from a union (and a bit tricky when joining is involved; here, the ORM switches from an inner join in queryset #1 to an outer join in queryset #3 to account for the second query that has no joins). See the relevant docs.
Try union()
, available from Django 1.11 onwards:
qs1 = Calendar.objects.filter(assistants=customer).exclude(owner=customer)
qs2 = Calendar.objects.filter(owner=customer)
qs3 = qs1.union(qs2)
Upvotes: 0