Search code examples
pythondjangoobjectfiltermany-to-many

django filter many-to-many with given list


I would like to filter a Django model that is connected to a second model via a many-to-many intermediate relationship.

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

design and expected result

The result should be to select only Person A because he is connected to Groups with entries 1 AND 2 through the membership. I'd like to use Q objects for this kind of task.

Can anyone give me a hint?


Solution

  • I think you want all the Person objects which are in all the group Ids you will provide it to.

    Solution:

    from django.db.models import Q
    
    person_qs = Person.objects.exclude(~(Q(group__id=1) & Q(group__id=2)))
    

    Here, I used exclude to exclude all the group Ids which are not 1 and 2.

    If you have lots of group Ids, you can use reduce and operator to build the query in a single for-loop.

    from functools import reduce
    import operator
    
    query = reduce(operator.and_, (Q(group__id=group_id) for group_id in group_ids))
    
    persons_qs = Person.objects.exclude(~query)
    

    This, will form the query like Q(group__id=1) & Q(group_id=2) & (so on...)