我有两个模型,Product,与RatingEntry有一对多的关系:
>>> product_entries = models.Products.objects.all()
>>> annotated = product_entries.annotate(Count("ratingentry"))
>>> len(annotated)
210
>>> a = annotated.filter(ratingentry__count__lte = 10)
>>> b = annotated.filter(ratingentry__count__gt = 10)
>>> len(a)
10
>>> len(b)
200
>>> len(a | b)
10 //should be 210
如果我将a和b更改为列表并连接它们,则长度可以达到210。
知道这里发生了什么吗?
答案 0 :(得分:2)
我认为这种行为是Django对象关系映射中的一个错误。如果你看一下Django为你的查询生成的SQL,那么你会看到类似这样的东西:
>>> q1 = (Products.objects.annotate(num_ratings = Count('ratingentries'))
... .filter(num_ratings__gt = 10))
>>> q2 = (Products.objects.annotate(num_ratings = Count('ratingentries'))
... .exclude(num_ratings__gt = 10))
>>> print(str((q1 | q2).query))
SELECT `myapp_products`.`id`, COUNT(`myapp_ratingentries`.`id`) AS
`num_ratings` FROM `myapp_products` LEFT OUTER JOIN `myapp_ratingentries` ON
(`myapp_products`.`id` = `myapp_ratingentries`.`product_id`) GROUP BY
`myapp_products`.`id` HAVING COUNT(`myapp_ratingentries`.`id`) > 10
ORDER BY NULL
请注意q1
中的条件包含在查询的HAVING
子句中,但q2
中的条件已丢失。
您可以通过以下方式构建查询来解决此问题:
>>> q = Q(num_products__gt = 10) | ~Q(num_products__gt = 10)
>>> q3 = Products.objects.annotate(num_ratings = Count('ratingentries')).filter(q)
>>> print(str(q3.query))
SELECT `myapp_products`.`id`, COUNT(`myapp_ratingentries`.`id`) AS
`num_ratings` FROM `myapp_products` LEFT OUTER JOIN `myapp_ratingentries` ON
(`myapp_products`.`id` = `myapp_ratingentries`.`product_id`) GROUP BY
`myapp_products`.`id` HAVING (COUNT(`myapp_ratingentries`.`id`) > 10 OR NOT
(COUNT(`myapp_ratingentries`.`id`) > 10 )) ORDER BY NULL
请注意,这两个条件现在都包含在HAVING
子句中。
我建议你report this to the Django developers as a bug。 (如果无法修复,那么至少应记录下来。)
答案 1 :(得分:-1)
Querysets不支持按位包含。 Django将其视为逻辑OR并返回评估True
的第一个,而不是引发错误。由于它们都是有效的查询集,因此始终返回第一个。
如果你想实际组合两个查询集,你需要将它们转换为列表然后用另一个扩展一个,或者使用像itertools.chain这样的东西,但你最终会得到一个不能生成的生成器用于除迭代之外的任何事情。无论哪种方式,组合查询集都将禁止对这些查询集进行任何进一步操作。