essin
essin

Reputation: 3

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?

Upvotes: 0

Views: 3800

Answers (2)

Sachin
Sachin

Reputation: 3674

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...)

Upvotes: 6

Daniel Roseman
Daniel Roseman

Reputation: 600041

There's no need to use Q here, it is a simple query.

Person.objects.filter(group__id__in=[1, 2])

Upvotes: 1

Related Questions