如何计算基于另一个查询集的多对多相关对象的计数?
How to calculate count of related many to many objects based on another queryset?
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.
,这意味着该查询集已就地执行。
也不起作用,但这次它只是 returns 无效值(总是 1,总是计算区域单个对象而不是过滤器内部的对象):
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
)
A .count()
在 Django 中被 eagerly 求值,所以 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__…))</b>
)
这里的 filter=Q(flight__…)
是您的航班过滤器的一部分。因此,如果 Flight
被假设的 active=True
过滤,您可以使用:
进行过滤
Zone.objects.annotate(
count=Count('flight', distinct=True, filter=<b>Q(flight__active=True)</b>)
)
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.
,这意味着该查询集已就地执行。
也不起作用,但这次它只是 returns 无效值(总是 1,总是计算区域单个对象而不是过滤器内部的对象):
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
)
A .count()
在 Django 中被 eagerly 求值,所以 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__…))</b>
)
这里的 filter=Q(flight__…)
是您的航班过滤器的一部分。因此,如果 Flight
被假设的 active=True
过滤,您可以使用:
Zone.objects.annotate(
count=Count('flight', distinct=True, filter=<b>Q(flight__active=True)</b>)
)