Django аннотировать набор запросов с подсчетом его членов по условию - PullRequest
1 голос
/ 08 июля 2020

У меня есть модель:

class Event(models.Model):
    start_date = DateTimeField()
    end_date = DateTimeField()

Я хочу подсчитать все события, относящиеся к одному и тому же дню, и включить это количество как поле аннотации daily_events для каждого члена набора запросов. Я хочу решить эту проблему на стороне базы данных для скорости. Мой код на данный момент:

from django.db.models import F, Q, DateTimeField, Count
from django.db.models.functions import TruncDate

events = Event.objects.all()
events = events.annotate(
    daily_events=Count('pk', filter=Q(start_date__date=TruncDate(F('start_date')))))
for event in events:
    print(event.daily_events)

Например, у меня есть 4 события и первые 3 в тот же день, поэтому желаемый результат должен быть:

3
3
3
1

, но текущий вывод неверен:

1
1
1
1

Есть какие-нибудь советы?

1 Ответ

0 голосов
/ 08 июля 2020

К сожалению, при вашем подходе возможно получить только агрегированные .values(), типа {start_date: '2020-10-10', daily_events: 3}. Если вам действительно нужны аннотированные объекты модели, это будет сложнее. Для достижения желаемых результатов можно использовать коррелированный подзапрос.

events = Event.objects.annotate(start_date_date=TruncDate('start_date'))
events_counts = events.values('start_date_date').annotate(daily_events=Count('*'))

subquery = events_counts.filter(start_date_date=OuterRef('start_date_date'))
events = events.annotate(daily_events=Subquery(subquery.values('daily_events'))

Изменить: добавлена ​​часть TruncDate

...