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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于ManyToMany过滤和组合查询集的非常奇怪的行为相关的知识,希望对你有一定的参考价值。

日历有一个所有者,并有一个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的结果是它们的实际并集。

答案

假设这是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。

另一答案

你正在做的是OR - 两个查询的WHERE子句,它们与union不同(并且在涉及加入时有点棘手;这里,ORM从查询集#1中的内部联接切换到查询集中的外部联接#3用于说明没有连接的第二个查询。请参阅相关的docs

尝试从Django 1.11起提供的union()

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

以上是关于关于ManyToMany过滤和组合查询集的非常奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

Django DRF视图过滤ManyToMany查询集

Hibernate:@ManyToMany 关系中对象集的传递持久性

Django:ManyToMany过滤器匹配列表中的所有项目

Elasticsearch的高阶使用方法有哪些?

Elasticsearch的高阶使用方法有哪些?

查询用于创建分组、聚合和过滤的行集的不同计数