是否可以在注释中进行过滤?
在我看来这样的事情(实际上并不起作用)
Student.objects.all().annotate(Count('attendance').filter(type="Excused"))
由此产生的表格将让每个学生都有理由缺席.查看文档过滤器只能在注释之前或之后进行,否则将无法产生所需的结果.
解决方法就是这样
for student in Student.objects.all():
student.num_excused_absence = Attendance.objects.filter(student=student, type="Excused").count()
Run Code Online (Sandbox Code Playgroud)
这可以工作,但在实际应用程序中执行很多查询,这可能会变得不切实际.我认为这种类型的语句在SQL中是可行的,但如果可能的话,我更愿意继续使用ORM.我甚至尝试过两个单独的查询(一个用于所有学生,另一个用于获得总数)并将它们与|组合.组合改变了总数:(
我在这里使用额外的SQL解决了出勤问题.
给定一个查询集,我用以下内容添加相关对象(ModelA)的计数:
qs = User.objets.all()
qs.annotate(modela__count=models.Count('modela'))
Run Code Online (Sandbox Code Playgroud)
但是,有没有办法计算只满足标准的ModelA?例如,计算ModelA,其中deleted_at为null?
我尝试了两种不能正常工作的解决方案.
1)正如@knbk建议的那样,在注释之前使用过滤器.
qs = User.objects.all().filter(modela__deleted_at__isnull=True).annotate(modela__count=models.Count('modela', distinct=True))
Run Code Online (Sandbox Code Playgroud)
这是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"
Run Code Online (Sandbox Code Playgroud)
问题来自WHERE子句.实际上,有一个LEFT JOIN,但后来的WHERE条件迫使它成为一个简单的JOIN.我需要将条件提升到JOIN子句中,以使其按预期工作.
所以,而不是
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
WHERE "modela"."deleted_at" IS NULL
Run Code Online (Sandbox Code Playgroud)
当我在纯SQL中直接执行它时,我需要以下内容.
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
AND "modela"."deleted_at" IS NULL
Run Code Online (Sandbox Code Playgroud)
如何在不执行原始查询的情况下更改查询集以获取此值?
2)正如其他人所说,我可以使用条件聚合.
我尝试了以下方法:
qs = User.objects.all().annotate(modela__count=models.Count(Case(When(modela__deleted_at__isnull=True, then=1))))
Run Code Online (Sandbox Code Playgroud)
变成以下SQL查询:
SELECT COUNT(CASE …Run Code Online (Sandbox Code Playgroud) 关于 SO 有很多类似的问题,但是这个特定的错误消息没有出现在我的任何搜索中:
AttributeError: 'WhereNode' object has no attribute 'select_format'
Run Code Online (Sandbox Code Playgroud)
当尝试使用annotate()比较(布尔)结果的 Django 查询集时会引发此问题,例如以下简化示例中的gt 查找:
Score.objects.annotate(positive=Q(value__gt=0))
Run Code Online (Sandbox Code Playgroud)
该模型如下所示:
class Score(models.Model):
value = models.FloatField()
...
Run Code Online (Sandbox Code Playgroud)
如何解决这个问题?