Аннотация Django не группирует вывод по назначению

Ниже приведена моя модель:

class Project(models.Model):
     name = models.CharField(max_length=1000, null=True, blank=True)
     date_created = models.DateTimeField(auto_now=True)
     status = models.CharField(max_length=1000, null=True, blank=True)

Поле статуса имеет около 5 различных вариантов (Выиграл, Проиграл, Открыт, Ожидает, Отменен).

Мне нужно знать, как получить количество проектов со статусом x в каждом месяце в заданном временном диапазоне запроса.

Я смог получить правильную форму данных, используя следующую аннотацию, но по какой-то причине в результате получается объект для каждого найденного статуса в течение месяца. Например, если в одном и том же месяце найдено как минимум 1 проект "Выигран" и 1 проект "Открыт", то для одного и того же месяца будет получено два отдельных объекта. Кроме того, параметры статуса здесь жестко закодированы и должны быть изменены, если будет добавлен новый статус.

queryset = list(opps.annotate(
    month=TruncMonth('date_created'),
).values('month').annotate(
    total=Count('id'),
    Win=Count('id', filter=Q(status='Win')),
    Loss=Count('id', filter=Q(status='Loss')),
    Open=Count('id', filter=Q(status='Open')),
    Dormant=Count('id', filter=Q(status='Dormant')),
    Pending=Count('id', filter=Q(status='Pending')),
    Cancelled=Count('id', filter=Q(status='Cancelled')),
))

Вот пример моего текущего вывода.

[{'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}
{'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 1, 'Open': 0, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}
{'month': datetime.datetime(2022, 5, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}
{'month': datetime.datetime(2022, 6, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'total': 1, 'Win': 0, 'Loss': 0, 'Open': 1, 'Dormant': 0, 'Pending': 0, 'Cancelled': 0}]

Если ваша Модель не определяет упорядочивание через класс Meta, вы должны указать упорядочивание перед вторым вызовом annotate.

queryset = list(opps
                .annotate(month=TruncMonth('date_created'))
                .order_by('month')  # <== this is necessary for the correct results
                .values('month')
                .annotate(total=Count('id'),
                          Win=Count('id', filter=Q(status='Win')),
                          Loss=Count('id', filter=Q(status='Loss')),
                          Open=Count('id', filter=Q(status='Open')),
                          Dormant=Count('id', filter=Q(status='Dormant')),
                          Pending=Count('id', filter=Q(status='Pending')),
                          Cancelled=Count('id', filter=Q(status='Cancelled'))))
Вернуться на верх