所以我有相当于这个的模型(非常简化,显然):
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 都包含最大数量的参与者。正在运行的实际查询的相关部分如下所示:
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()不会也永远不会允许你设置 HAVING 参数。
有没有办法让 Django 的 ORM 做我想做的事?