Django аннотируют модели с совокупным значением на основе запроса

Допустим, у меня есть следующая структура модели:

Parent():

Child():
parent = ForeignKey(Parent)

GrandChild():
child = ForeignKey(Child)
state = BooleanField()
num = FloatField()

Я пытаюсь от родителя ViewSet, восстановите следующее:

  1. Количество детей.
  2. Сумма полей 'num', когда 'state' - True.

Я могу сделать следующее:

queryset = Parent.objects\
    .annotate(child_count=Count('child'))\
    .annotate(sum_total=Sum('child__grandchild__num'))

Это дает мне (1), но вместо (2) это дает мне СУММУ для ВСЕХ внуков. Как я могу отфильтровать внуков должным образом, при этом у меня есть все Parent объекты еще в QuerySet?

3 ответа

Какую версию Django вы используете? Вы также можете использовать подзапрос, если поддерживается версия.

Parent.objects
.annotate(child_count=Count('child'))
.annotate(
    grandchild_count_for_state_true=Subquery(
        GrandChild.objects.filter(
            state=True,
            child=OuterRef('pk')
        ).values('parent')
        .annotate(cnt=Sum('child__grandchild__num'))
        .values('cnt'),
        num=models.IntegerField()
    )
)

Вы можете оптимизировать это с помощью запроса агрегации.

Попробуйте использовать фильтр до аннотации

queryset = Parent.objects.filter(child__grandchild__state=True')\
    .annotate(child_count=Count('child'))\
    .annotate(sum_total=Sum('child__grandchild__num'))

Вы можете сделать следующее:

      qs = Parents.objects.all()
child_count = Count('children')
num_sum = Sum('children__grandchildren__num', filter=Q(children__grandchildren__state=True))
qs = qs.annotate(child_count=child_count).annotate(num_sum=num_sum)

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

Другие вопросы по тегам