所以我有相当于这个的模型(显然非常简化):
class Mystery(models.Model):
name = models.CharField(max_length=100)
class Character(models.Model):
mystery = models.ForeignKey(Mystery, related_name="characters")
required = models.BooleanField(default=True)
基本上,在每一个谜团中都有许多角色,这些角色对于故事是否至关重要。能够揭开神秘面纱的最小演员数量是这个神秘所需的角色数量;最大数字是神秘的总字符数。
现在我正在尝试查询某些特定演员可以演奏的谜团。使用Django的过滤和注释功能的方式似乎很简单;毕竟,这两个查询都可以正常工作:
# Returns mystery objects with at least x characters in all
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).filter(max_actors__gte=x)
# Returns mystery objects with no more than x required characters
Mystery.objects.filter(characters__required=True).annotate(min_actors=Count('characters', distinct=True)).filter(min_actors__lte=x)
但是,当我尝试将两者合并时......
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).filter(characters__required=True).annotate(min_actors=Count('characters', distinct=True)).filter(min_actors__lte=x, max_actors__gte=x)
......它不起作用。 min_actors和max_actors都包含最大数量的actor。正在运行的实际查询的相关部分如下所示:
SELECT `mysteries_mystery`.`id`,
`mysteries_mystery`.`name`,
COUNT(DISTINCT `mysteries_character`.`id`) AS `max_actors`,
COUNT(DISTINCT `mysteries_character`.`id`) AS `min_actors`
FROM `mysteries_mystery`
LEFT OUTER JOIN `mysteries_character` ON (`mysteries_mystery`.`id` = `mysteries_character`.`mystery_id`)
INNER JOIN `mysteries_character` T5 ON (`mysteries_mystery`.`id` = T5.`mystery_id`)
WHERE T5.`required` = True
GROUP BY `mysteries_mystery`.`id`, `mysteries_mystery`.`name`
...这清楚地表明,当Django在字符表上创建第二个连接时(表的第二个副本被别名为T5),该表实际上并未在任何地方使用,而且两个从非别名版本中选择计数,这显然会产生相同的结果。
即使我尝试使用extra
子句从T5中进行选择,我也会被告知没有T5这样的表,即使检查输出查询显示它仍然将第二个字符表别名为T5。使用extra
子句执行此操作的另一种尝试是这样的:
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).extra(select={'min_actors': "SELECT COUNT(*) FROM mysteries_character WHERE required = True AND mystery_id = mysteries_mystery.id"}).extra(where=["`min_actors` <= %s", "`max_actors` >= %s"], params=[x, x])
但这不起作用,因为我不能在WHERE子句中使用计算字段,至少在MySQL上。如果我只能使用HAVING,但是唉,Django的.extra()does not and will never允许你设置HAVING参数。
有没有办法让Django的ORM做我想做的事?
答案 0 :(得分:0)
如何组合你的Count()s:
Mystery.objects.annotate(max_actors=Count('characters', distinct=True),min_actors=Count('characters', distinct=True)).filter(characters__required=True).filter(min_actors__lte=x, max_actors__gte=x)
这似乎对我有用,但我没有用您的确切型号进行测试。
答案 1 :(得分:0)
已经有几个星期没有建议的解决方案了,所以这就是我最终要做的事情,对于其他可能正在寻找答案的人来说:
Mystery.objects.annotate(max_actors=Count('characters', distinct=True)).filter(max_actors__gte=x, id__in=Mystery.objects.filter(characters__required=True).annotate(min_actors=Count('characters', distinct=True)).filter(min_actors__lte=x).values('id'))
换句话说,过滤第一个计数和与匹配第二个计数的显式子查询中的ID匹配的ID。有点笨重,但它适合我的目的。