为了简单起见我有四个表(A,B,类别和关系),关系表在B中存储A的强度,而类别存储B的类型。
A <--- Relation ---> B ---> Category
(所以A和B之间的关系是n到n,其中B和Category之间的关系是n到1)
我需要的是计算使用以下方法获得的类别中A的发生率:
A.objects.values(
'id', 'relation_set__B__Category_id'
).annotate(
ANum = Count('id', distinct=False)
)
请注意,如果我使用&#39; distinct = True&#39;相反,每一个和每一个Anum&#39;等于1,这不是理想的结果。问题是我必须根据B发生的日期(以及B表中的其他一些字段)过滤计算, 我正在使用django 2.0的功能,这使using filter as an argument in aggregation成为可能。 我们假设:
kwargs= {}
kwargs['relation_set__B____BDate__gte'] = the_start_limit
我可以在我的代码中使用它,如:
A.objects.values(
'id', 'relation_set__B__Category_id'
).annotate(
Anum = Count('id', distinct=False, filter=Q(**kwargs))
)
然而,由于表连接,我得到的结果是重复的,我不能使用distinct = True,正如我解释的那样。 (查询A也是必须的,因为我必须按照我的question here中的说明聚合此表中的其他一些字段)
我正在使用Postgres和django 2.0.1。
是否有任何变通方法可以实现我的想法?
更新
使用另一个子查询完成它:
# subquery
annotation = {
'ANum': Count('relation_set__A_id', distinct=False,
filter=Q(**Bkwargs),
}
sub_filter = Q(relation_set__A_id=OuterRef('id')) &
Q(Category_id=OuterRef('relation_set__B__Category_id'))
# you could annotate 'relation_set__B__Category_id' to A query an set the field here.
subquery = B.objects.filter(
sub_filter
).values(
'relation_set__A_id'
).annotate(**annotation).values('ANum')[:1]
# main query
A.objects.values(
'id', 'relation_set__B__Category_id'
).annotate(
Anum = Subquery(subquery)
)
答案 0 :(得分:1)
我还不确定我是否明白你想要的东西。你写了
请注意,如果我使用&#39; distinct = True&#39;相反,每一个和每一个Anum&#39;将等于1
当然。您将关联的A对象计数到每个A对象。每个都是自我的。所以我仍然认为你不想用Anum
注释A对象,但可能是类别。这个应该在每个类别中为您提供所需数量的As。
Category.objects.annotate(
Anum=Count(
'b__relation__a',
filter=Q(b__BDate__gte=the_start_limit),
distinct=True
)
)
'b__relation__a'
跟在relations backwards之后,并选择与该类别相关的所有A对象。但是,过滤器将计算的关系限制为某些Bs。需要distinct=True
才能避免query bug。
如果你真的想要&#34;按其id&#34;分组的A对象列表(并且不仅仅是汇总的Anum
- 计数),正如您在评论中所述,我在单个查询中看不到一种简单的方法。