Consider simple Django models Event
and 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)
It's easy to annotate events query with total number of participants:
events = Event.objects.all().annotate(participants=models.Count('participant'))
How to annotate with count of participants filtered by is_paid=True
?
I need to query all events regardless of number of participants, e.g. I don't need to filter by annotated result. If there are 0
participants, that's ok, I just need 0
in annotated value.
The example from documentation doesn't work here, because it excludes objects from query instead of annotating them with 0
.
Update. Django 1.8 has new conditional expressions feature, so now we can do like this:
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 2. Django 2.0 has new Conditional aggregation feature, see the accepted answer below.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…