5 Stimmen

Django M2M QuerySet Filterung auf mehrere Fremdschlüssel

Ich habe diese beiden Klassen für ein Messaging-Modul, an dem ich arbeite. Die Idee ist, dass eine Unterhaltung durch eine Gruppe von Teilnehmern (zwei oder mehr) dargestellt wird. Ich kämpfe damit, eine Möglichkeit zu finden, eine Konversation nach der Logik zu suchen, die besagt, dass die gewünschte Konversation, die ich zu finden versuche, die folgenden Teilnehmer hat. Ich habe versucht Conversation.objects.filter(participants__in=[p1, p2]) Dies ist jedoch eine ODER-ähnliche Abfrage: p1 ist ein Teilnehmer oder p2 ist ein Teilnehmer. Ich möchte p1 und p2 und ... pN ist ein Teilnehmer. Kann mir da jemand helfen?

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

0voto

Ohad Punkte 1719

Als erstes würde ich einen verwandten Namen in die participants Feld:

participants = models.ManyToManyField(User, related_name='conversations')

Dies ist nicht notwendig, aber IMO besser lesbar.

Dann können Sie etwas tun wie:

p1.conversations.filter(participants__in=p2)

Dies gibt alle Gespräche von p1 zurück, an denen auch p2 beteiligt ist.

Ich bin mir über die DB-Effizienz dieser Filtermethode nicht sicher, und vielleicht ist die Verwendung einer anderen Art von Datenbank (vielleicht eine Graph-DB wie Neo4j) besser geeignet.

0voto

Raunak Agarwal Punkte 7037

Eine Möglichkeit, dies zu tun, könnte die Verwendung von Python-Sets sein:

#Get the set of conversation ids for each participant
    p1_conv_set = set(Converstation.objects.filter(participants = p1).values_list('id', flat=True))
    p2_conv_set = set(Converstation.objects.filter(participants = p2).values_list('id', flat=True))
    .
    .
    pn_conv_set = set(Converstation.objects.filter(participants = pN).values_list('id', flat=True))
    #Find the common ids for all participants
    all_participants_intersection = p1_conv_set & p2_conv_set & ....pN_conv_set
    #Get all the conversation for all the calculated ids
    Conversation.objects.filter(id__in = all_participants_intersection)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X