Django M2M QuerySet filtering on multiple foreign keys

django, django-queryset, many-to-many, python

Solution

I think you just need to iteratively filter. This could be utter nonsense as I'm a bit sleep deprived, but maybe a manager method like so:

class ConversationManager(models.Manager):
    def has_all(self, participants):
        # Start with all conversations
        reducedQs = self.get_query_set()
        for p in participants:
            # Reduce to conversations that have a participant "p" 
            reducedQs = reducedQs.filter(participants__id=p.id)
        return reducedQs

Generally speaking, you should get in the habit of making table-level queries manager methods, as opposed to class methods. And by doing it this way, you're left with a queryset that you can filter further if need be.

Inspired by the query of all Groups that have a member name Paul in the documentation and this answer.

Problem

I have these two classes for a messaging module I'm working on. The idea is that a conversation is represented by a group of participants (two or more). I'm struggling to find a way to look up a conversation by the logic saying that the desired conversation I'm trying to find has the following participants. I tried `Conversation.objects.filter(participants__in=[p1, p2])` however this does an OR style query, p1 is a participant or p2 is a participant. I want p1 and p2 and... pN is a participant. Any help out there? ``` class Conversation(models.Model): date_started = models.DateTimeField(auto_now_add=True) participants = models.ManyToManyField(User) def get_messages(self): return Message.objects.filter(conversation=self) def new_message(self, sender, body): Message.objects.create(sender=sender, body=body, conversation=self) self.save() class Message(models.Model): sender = models.ForeignKey(User) body = models.TextField() date = models.DateTimeField(auto_now_add=True) conversation = models.ForeignKey(Conversation) def __unicodde__(self): return body + "-" + sender ```

Original source

Related problems