Given roughly these two models:
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'
)
For all persons I want to get the count of resources he/she is either contributing to OR involved in.
I tried the following:
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)
This gives me a list of tuples like this:
[
# (id, name, count)
(1, 'John Doe', 12),
(2, 'Jane Doe', 5),
(3, 'Donald Trump', 3),
]
However if a person is both contributing and involved the resource will be counted twice because the resource will be joined twice to the person table. What I want is the resource to be counted only once if it is present in both relationships.
How do I have to change my queryset to prevent this?
I am using postgresql and Django 1.11.
Counting entries that are appearing in either of relations can be achieved by counting entries from 1st relation + counting entries from 2nd relation - counting entries from both relations. That can be achieved in Django by this queryset:
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')
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.