Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django M2M QuerySet filtering on multiple foreign keys

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 
like image 713
Mike Avatar asked Dec 01 '12 21:12

Mike


1 Answers

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.

like image 172
acjay Avatar answered Nov 15 '22 03:11

acjay