如何过滤Django中的计数注释对象?

考虑简单的Django模型EventParticipant

 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注释它们。

更新。 Django 1.8有新的条件expression式function ,所以现在我们可以这样做:

 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 1.8有新的条件expression式function ,所以现在我们可以这样做:

 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() ))) 

UPDATE

我提到的子查询方法现在通过子查询expression式支持Django 1.11。

 Event.objects.annotate( num_paid_participants=Subquery( Participant.objects.filter( is_paid=True, event=OuterRef('pk') ).values('event') .annotate(cnt=Count('pk')) .values('cnt'), output_field=models.IntegerField() ) ) 

我更喜欢这个聚合(总和+情况) ,因为它应该更快,更容易被优化(适当的索引)

对于旧版本,使用.extra可以实现相同的.extra

 Event.objects.extra(select={'num_paid_participants': "\ SELECT COUNT(*) \ FROM `myapp_participant` \ WHERE `myapp_participant`.`is_paid` = 1 AND \ `myapp_participant`.`event_id` = `myapp_event`.`id`" })