Как рассчитать количество связанных много-много объектов на основе другого набора запросов? - PullRequest
1 голос
/ 23 сентября 2019
class Zone(Model):
  ...

class Flight(Model):
  zones = ManyToManyField(Zone)

flights = Flight.objects.filter(...)
qs1 = Zone.objects.annotate(
   count=flights.filter(zones__pk=F('pk')).distinct().count(),  # this is not valid expression
)

Несмотря на наличие F внутри набора запросов с count() в аннотации, он по-прежнему выдает ошибку TypeError: QuerySet.annotate() received non-expression(s): 0., означающую, что этот набор запросов был выполнен на месте.

Также не работает, но этораз он просто возвращает недопустимое значение (всегда 1, всегда считая один объект Zone вместо того, что внутри фильтра):

qs1 = Zone.objects.annotate(
   count=Count('pk', filter=flights.filter(zones__pk=F('pk'))),  # with 'flight' instead of first 'pk' it also doesn't work
)

1 Ответ

1 голос
/ 23 сентября 2019

A .count() оценивается с нетерпением в Django, поэтому Django попытается оценить flights.filter(zones__pk=F('pk')).distinct().count(), и преуспеет в этом, поскольку F('pk') будет подсчитывать число fligts там, гдеzones имеют тот же первичный ключ, что и первичный ключ Flight.Вам нужно будет использовать OuterRef [Django-doc] и .annotate(..) в подзапросе.

Но вы делаете это слишком сложным.Вы можете просто комментировать:

from django.db.models import Q, Sum

Zone.objects.annotate(
    <b>count=Count('flight', distinct=True, filter=Q(flight__&hellip;))</b>
)

Здесь filter=Q(flight__&hellip;) является частью фильтра ваших рейсов.Таким образом, если Flight s фильтруются по гипотетическому active=True, вы фильтруете с помощью:

Zone.objects.annotate(
    count=Count('flight', distinct=True, filter=<b>Q(flight__active=True)</b>)
)
...