是否可以在注释中进行过滤?
在我看来这样的事情(实际上并不起作用)
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()
这有效,但在实际应用程序中进行了很多查询,这可能会变得不切实际。我认为这种类型的语句在SQL中是可行的,但如果可能的话,我更愿意继续使用ORM。我甚至尝试过两个单独的查询(一个用于所有学生,另一个用于获得总数)并将它们与|组合。这个组合改变了总数:(
我使用额外的sql here解决了出勤问题。
答案 0 :(得分:15)
从Django 1.8开始,您可以直接在ORM中执行此操作:
students = Student.objects.all().annotate(num_excused_absences=models.Sum(
models.Case(
models.When(absence__type='Excused', then=1),
default=0,
output_field=models.IntegerField()
)))
根据another SO question on the same topic
改编的答案我还没有对上面的示例进行测试,但确实在我自己的应用程序中完成了类似的工作。
答案 1 :(得分:5)
你是对的 - django不允许你过滤被计数的相关对象,也不允许将过滤器应用于主要对象,因此在过滤后排除那些没有相关对象的主要对象。
但是,在一些抽象泄漏中,您可以使用值查询来计算组。
所以,我在字典中收集缺席,并在循环中使用它。像这样:
# a query for students
students = Students.objects.all()
# a query to count the student attendances, grouped by type.
attendance_counts = Attendence(student__in=students).values('student', 'type').annotate(abs=Count('pk'))
# regroup that into a dictionary {student -> { type -> count }}
from itertools import groupby
attendance_s_t = dict((s, (dict(t, c) for (s, t, c) in g)) for s, g in groupby(attendance_counts, lambda (s, t, c): s))
# then use them efficiently:
for student in students:
student.absences = attendance_s_t.get(student.pk, {}).get('Excused', 0)
答案 2 :(得分:-3)
也许这对你有用:
excused = Student.objects.filter(attendance__type='Excused').annotate(abs=Count('attendance'))
您需要首先过滤您正在寻找的学生,然后过滤那些有缺席的学生,然后注明他们的数量。
以下是Django Aggregation Docs的链接,其中讨论了过滤顺序。