Подсчет по месяцам в запросе Django

Добрый день,

Я борюсь с запросом. В конечном счете, у меня есть несколько записей, которые я хочу запросить и получить подсчет по месяцам.

В конечном счете, моя цель - получить набор данных, который выглядит следующим образом:

Month, opened, closed
Jan, 2, 3
Feb, 1, 5

И так далее... за последние шесть месяцев.

Я использовал это в качестве основы: Django: Query Group By Month

Это работает для получения каждого по отдельности:

six_months_ago = datetime.now() - timedelta(days = 180)
open_six_months = (Rec.objects
   .annotate(open=Month('open_date'))
   .values('open')
   .annotate(rec_opened=Count('status', filter=Q(status__is_open=True)))
   .order_by())
        
closed_six_months = (Rec.objects
   .annotate(closed=Month('close_date'))
   .values('closed')
   .annotate(rec_closed=Count('status', filter=Q(status__is_open=False) and Q(close_date__isnull=False) ))
   .order_by())

Еще не все записи имеют дату закрытия.

При тестировании возвращаются правильные данные, но в двух разных запросах.

Я хотел бы иметь один единственный набор данных, если это возможно.

Есть ли простой способ объединить это в один запрос, который содержит одну строку с подсчетом даты открытия и подсчетом даты закрытия по месяцам?

Спасибо за помощь.

BCBB

Можно просто соединить две части вместе следующим образом:

from django.db.models import IntegerField, Q, Value
from django.db.models.functions import ExtractMonth

six_months_ago = datetime.now() - timedelta(days=180)
all_items = (
    Rec.objects.values(
        open=ExtractMonth('open_date'),
        closed=Value(None, output_field=IntegerField()),
    )
    .annotate(item=Count('status', filter=Q(status__is_open=True)))
    .order_by()
    .union(
        Rec.objects.values(
            open=Value(None, output_field=IntegerField()),
            closed=ExtractMonth('close_date'),
        )
        .annotate(
            item=Count(
                'status',
                filter=Q(status__is_open=False, close_date__isnull=False),
            )
        )
        .order_by(),
        all=True,
    )
)

тогда мы выполняем постобработку следующим образом:

result = {}
for item in all_items:
    month = item['open'] or item['close']
    record = result.setdefault(month, [0, 0])
    record[item['open'] is None] += item['item']

В этом случае каждый номер месяца будет отображаться в списке из двух элементов, первый из которых - количество предметов, открытых в этом месяце, а второй - количество предметов, закрытых в этом месяце.

Вернуться на верх