简体   繁体   English

如何在Django中计算与同一个模型的两个m2m关系上的相关实体的数量

[英]How to count the number of related entities over two m2m relations to the same Model in Django

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. 但是,如果一个人同时在参与和参与,则该资源将被计数两次,因为该资源将两次被连接到person表。 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. 我正在使用postgresql和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: 可以通过以下查询集在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')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM