【发布时间】:2015-06-09 00:38:35
【问题描述】:
给定一个查询集,我将相关对象 (ModelA) 的计数添加到以下内容:
qs = User.objets.all()
qs.annotate(modela__count=models.Count('modela'))
但是,有没有办法计算仅满足条件的 ModelA?例如,计算deleted_at为null的ModelA?
我尝试了两种无法正常工作的解决方案。
1) 正如@knbk 建议的那样,在注释之前使用过滤器。
qs = User.objects.all().filter(modela__deleted_at__isnull=True).annotate(modela__count=models.Count('modela', distinct=True))
这里是 django 生成的查询的简化版本:
SELECT COUNT(DISTINCT "modela"."id") AS "modela__count", "users".*
FROM "users"
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
WHERE "modela"."deleted_at" IS NULL
GROUP BY "users"."id"
问题来自 WHERE 子句。 事实上,有一个 LEFT JOIN,但后来的 WHERE 条件迫使它成为一个普通的 JOIN。我需要将条件拉到 JOIN 子句中以使其按预期工作。
所以,而不是
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
WHERE "modela"."deleted_at" IS NULL
当我直接在普通 SQL 中执行它时,我需要以下内容。
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
AND "modela"."deleted_at" IS NULL
如何在不进行原始查询的情况下更改查询集以获取此信息?
2) 正如其他人所建议的,我可以使用条件聚合。
我尝试了以下方法:
qs = User.objects.all().annotate(modela__count=models.Count(Case(When(modela__deleted_at__isnull=True, then=1))))
变成下面的 SQL 查询:
SELECT COUNT(CASE WHEN "modela"."deleted_at" IS NULL THEN 1 ELSE NULL END) AS "modela__count", "users".*
FROM "users" LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
GROUP BY "users"."id"
通过这样做,我得到了所有用户(因此 LEFT JOIN 正常工作),但对于根本没有任何 ModelA 的所有用户,modela__count 得到“1”(而不是 0)。
如果没有什么可数的,为什么我得到 1 而不是 0?
怎么改?
【问题讨论】:
标签: django django-models django-queryset