Django Filter viele-zu-viele mit enthält

87

Ich versuche, eine Reihe von Objekten durch eine Viele-zu-Viele-Beziehung zu filtern. Da das trigger_rolesFeld mehrere Einträge enthalten kann, habe ich den containsFilter ausprobiert . Aber da das für die Verwendung mit Strings ausgelegt ist, bin ich ziemlich hilflos, wie ich diese Beziehung filtern soll (Sie können die values_list()atm ignorieren .).

Diese Funktion ist an das Benutzerprofil angehängt:

def getVisiblePackages(self):
    visiblePackages = {}   
    for product in self.products.all():
        moduleDict = {}
        for module in product.module_set.all():
            pkgList = []
            involvedStatus = module.workflow_set.filter(trigger_roles__contains=self.role.id,allowed=True).values_list('current_state', flat=True)

Mein Workflow-Modell sieht folgendermaßen aus (vereinfacht):

class Workflow(models.Model):
    module = models.ForeignKey(Module)
    current_state = models.ForeignKey(Status)
    next_state = models.ForeignKey(Status)
    allowed = models.BooleanField(default=False)
    involved_roles = models.ManyToManyField(Role, blank=True, null=True)
    trigger_roles = models.ManyToManyField(Role, blank=True, null=True)

Obwohl die Lösung ziemlich einfach sein mag, wird mein Gehirn es mir nicht sagen.

Danke für Ihre Hilfe.

Grave_Jumper
quelle

Antworten:

109

Haben Sie so etwas versucht:

module.workflow_set.filter(trigger_roles__in=[self.role], allowed=True)

oder nur wenn self.role.ides keine liste von pks gibt:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)
Mouad
quelle
1
Das scheint nicht zu funktionieren. Da die self.role.id nur ein int ist und die trigger_roles eine Liste von ihnen ist, würde ich ein invertiertes In benötigen, wie enthält, aber wie ich herausgefunden habe, ist enthält nur für Zeichenfolgen.
Grave_Jumper
8
Das zweite Beispiel sollte funktionieren. Wenn der Wert in self.role.ideine der Trigger-Rollen ist, sollte dieser Filter alle Workflows abrufen, bei denen eine der Trigger-Rollen der Wert in ist self.role.id. Grundsätzlich verhält sich dies genau wie eine "enthält" -Funktion. Es sei denn, wir vermissen alle etwas.
Jordan Reiter
@Jordan Reiter: "enthält" wird in SQL in "wie" konvertiert, was nicht das ist, was das OP will, und ich denke, er weist bereits darauf hin, andererseits wird "genau" in "=" oder "ist" konvertiert, was das ist Idee hier.
Mouad
@Grave_Jumper: Schauen Sie hier ( djangoproject.com/documentation/models/many_to_many ). Sie können ein Beispiel für die Arbeit mit ManytoMany Field finden. Ich hoffe, dies kann Ihnen helfen, wenn meine Antwort nicht lautet :)
mouad
1
aww .. sorry deine zweite Lösung funktioniert ziemlich gut :) Es gab eine kleine Fehlkonfiguration auf meiner Seite. Danke Jungs, das hat mir den Tag gerettet
;-)
18

Der einfachste Ansatz, um dies zu erreichen, wäre die Überprüfung der gesamten Instanz (anstelle der ID) auf Gleichheit in der ManyToManyField. Das sieht so aus, als ob sich die Instanz innerhalb der Viele-zu-Viele-Beziehung befindet. Beispiel:

module.workflow_set.filter(trigger_roles=self.role, allowed=True)
Caumons
quelle
6

Ich weiß, dass dies eine alte Frage ist, aber es sieht so aus, als hätte das OP nie die Antwort bekommen, nach der er gesucht hat. Wenn Sie zwei Sätze von ManyToManyFields haben, die Sie vergleichen möchten, besteht der Trick darin, den __inOperator zu verwenden, nicht contains. Wenn Sie beispielsweise ein "Ereignis" -Modell mit einem ManyToMany zu "Gruppe" im Feld eventgroupshaben und Ihr Benutzermodell (offensichtlich) an eine Gruppe angehängt ist, können Sie Folgendes abfragen:

Event.objects.filter(eventgroups__in=u.groups.all())

Shacker
quelle
4

Singularität ist mit dem ersten Beispiel fast richtig. Sie müssen nur sicherstellen, dass es sich um eine Liste handelt. Das zweite Beispiel, das Überprüfen, trigger_roles__id__exactist jedoch eine bessere Lösung.

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
Josh Smeaton
quelle