Рассмотрим простые модели Django Event
и Participant
:Как фильтровать объекты для аннотации счетчика в Django?
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
?
Мне нужно запросить все события независимо от количества участников, например. Мне не нужно фильтровать аннотированный результат. Если есть 0
участников, это нормально, мне просто нужно 0
в аннотированном значении.
example from documentation здесь не работает, поскольку он исключает объекты из запроса вместо аннотирования их 0
.
Обновление. Django 1.8 имеет новый conditional expressions feature, так что теперь мы можем сделать так:
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 имеет новую функцию Conditional aggregation см the accepted answer ниже.
Это выглядит потрясающе! :) – rudyryk
Кстати, нет такого примера по ссылке на документацию, показывается только «агрегатное» использование. Вы уже тестировали такие запросы? (У меня нет и я хочу верить! :) – rudyryk
У меня есть. Они работают. Я на самом деле попал в странный патч, где старый (супер сложный) подзапрос прекратил работать после обновления до Django 2.0, и мне удалось заменить его супер-простым отфильтрованным счетом. В аннотациях есть более эффективный пример in-doc, поэтому я сейчас задержу это. – Oli