Python Django:注释不起作用?
我有两个模型,Product,它与RatingEntry有一对多的关系:Python Django:注释不起作用?,python,django,annotations,Python,Django,Annotations,我有两个模型,Product,它与RatingEntry有一对多的关系: >>> product_entries = models.Products.objects.all() >>> annotated = product_entries.annotate(Count("ratingentry")) >>> len(annotated) 210 >>> a = annotated.filter(ratingentry__c
>>> 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
知道这里发生了什么吗?查询集不支持按位包含。Django不会引发错误,而是将其视为逻辑OR,并返回第一个计算值
True
。因为它们都是有效的查询集,所以总是返回第一个查询集
如果您想实际合并两个查询集,您要么需要将它们转换为列表,然后将其中一个扩展为另一个,要么使用类似itertools.chain的东西,但最终将得到一个生成器,它只能用于迭代。无论哪种方式,组合查询集都将禁止对这些查询集执行任何进一步的操作。我认为这种行为是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
>>> 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
请注意,q1
中的条件包含在查询的HAVING
子句中,但是q2
中的条件已丢失
您可以通过如下方式构建查询来解决此问题:
>>> 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
>>> 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
子句中
我建议你。(如果无法修复,那么至少应该记录下来。)我认为这是不对的,我以前使用此运算符组合了QuerySet,结果成功了。例如:>>>a=models.Product.objects.filter(kind=“costs”)>>>b=models.Product.objects.filter(kind=“technology”)>>>len(a)90>>len(b)113>>>len(a | b)203>>你可以做
a=Q(ratingentry\uu count\uu lte=10);b=Q(比率入口计数=10);annotated.filter(a | b)
这个解释很有道理,我会尽量确保这不是我犯的愚蠢错误,并对此进行报告。