大致给出这两个模型:
class Person(models.Model):
name = models.CharField()
class Resource(models.Model):
people_contributing = models.ManyToManyField(
Person,
related_name='resouces_contributing_to'
)
people_involved = models.ManyToManyField(
Person,
related_name='resources_involved_in'
)
对于所有想要获得资源数量的人,他/她要么参与 OR 。
我尝试了以下内容:
resources = Resource.objects.all()
participations = Person.objects.filter(
Q(resources_contributing_to__in=resources) |
Q(resources_involved_in__in=resources)
).values(
# group results by person
'pk'
).annotate(
count=Count('id')
).values_list(
'pk',
'name',
'count'
).order_by('-count')
print(participations)
这给了我一个像这样的元组列表:
[
# (id, name, count)
(1, 'John Doe', 12),
(2, 'Jane Doe', 5),
(3, 'Donald Trump', 3),
]
但是,如果一个人既贡献又参与,则资源将被计算两次,因为资源将连接两次到人员表。我想要的是,如果资源只存在于两种关系中,那么它只被计算一次。
如何更改查询集以防止此情况?
我正在使用postgresql和Django 1.11。
答案 0 :(得分:2)
计算出现在任一关系中的条目可以通过计算第一关系中的条目+来自第二关系的计数条目来实现 - 计算来自两个关系的条目。这可以通过这个查询集在Django中实现:
participations = Person.objects.filter(
Q(resources_contributing_to__in=resources) |
Q(resources_involved_in__in=resources)
).annotate(
count=Count('resouces_contributing_to__id', distinct=True) + Count('resources_involved_in__id', distinct=True) - Count(Case(When(resources_involved_in__id=F('resouces_contributing_to__id'), then='resources_involved_in__id')), distinct=True),
).values_list(
'pk',
'name',
'count'
).order_by('-count')