考虑简单的Django模型Event和Participant:
Event
Participant
class Event(models.Model): title = models.CharField(max_length=100) class Participant(models.Model): event = models.ForeignKey(Event, db_index=True) is_paid = models.BooleanField(default=False, db_index=True)
使用参与者总数来注释事件查询很容易:
events = Event.objects.all().annotate(participants=models.Count('participant'))
如何用筛选的参与者计数进行注释is_paid=True?
is_paid=True
我需要查询所有事件,而与参与者人数无关,例如,我不需要按带注释的结果进行过滤。如果有0参与者,那没关系,我只需要带有0注释的值即可。
0
文档中的示例在这里不起作用,因为它从查询中排除了对象,而不是使用注释了对象0。
更新。Django 1.8具有新的条件表达式功能,因此我们现在可以像这样:
events = Event.objects.all().annotate(paid_participants=models.Sum( models.Case( models.When(participant__is_paid=True, then=1), default=0, output_field=models.IntegerField() )))
Django 2.0中的条件聚合使你可以进一步减少过去的流量。这也将使用Postgres的filter逻辑,该逻辑比求和的情况要快一些(我见过像20-30%这样的数字被打乱)。
无论如何,就你的情况而言,我们正在研究简单的东西:
from django.db.models import Q, Count events = Event.objects.annotate( paid_participants=Count('participants', filter=Q(participants__is_paid=True)) )
在文档中还有一个单独的部分,关于注释过滤。它和条件聚合是一样的东西,但是更像上面的例子。无论哪种方式,这都比我之前做的粗糙子查询要健康得多。
刚刚发现Django 1.8具有新的条件表达式功能,所以现在我们可以这样做: