关于ManyToMany过滤和合并查询集的非常奇怪的行为

时间:2019-04-18 10:30:11

标签: python django

日历有一个所有者,并且有一个ManyToMany字段“助手” 我有一个日历,有2位助手,其中一位是它的所有者。 我认为django shell中的这三行代码可以很好地解释怪异的行为。

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

当然希望queryset join的结果是它们的实际并集。

2 个答案:

答案 0 :(得分:1)

假设这是针对Django 1.11+:
|不代表联合。它代表两个查询集的OR组合(维持所有连接;因此aliz出现两次)。

qs1.filter(x=1) | qs2.exclude(x=1)转换为:

SELECT STUFF FROM TABLES_AND_JOINS WHERE (x = 1 OR NOT (x = 1))

qs1.filter(x=1).union(qs2.exclude(x=1))转换为:

SELECT STUFF FROM TABLE1 WHERE x = 1 UNION SELECT STUFF FROM TABLE2 WHERE NOT x = 1

使用str(qs.query)查看SQL。

答案 1 :(得分:0)

您正在做的是OR-进入两个查询的WHERE子句,这与并集是不同的(并且在涉及联接时有些棘手;这里,ORM从内部将查询集#1中的连接连接到查询集#3中的外部连接,以说明没有连接的第二个查询)。请参阅相关的docs

尝试union()(可从Django 1.11开始使用):

qs1 = Calendar.objects.filter(assistants=customer).exclude(owner=customer)                             
qs2 = Calendar.objects.filter(owner=customer) 
qs3 = qs1.union(qs2)