Django filtro molti-a-molti con contiene


90

Sto cercando di filtrare un gruppo di oggetti attraverso una relazione molti-a-molti. Poiché il trigger_rolescampo può contenere più voci, ho provato il containsfiltro. Ma poiché è progettato per essere utilizzato con le stringhe, sono praticamente impotente su come filtrare questa relazione (puoi ignorare l' values_list()atmosfera.).

Questa funzione è collegata al profilo utente:

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)

Il mio modello di flusso di lavoro è simile a questo (semplificato):

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)

Anche se la soluzione potrebbe essere abbastanza semplice, il mio cervello non me lo dice.

Grazie per l'aiuto.

Risposte:


110

Hai provato qualcosa di simile:

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

o semplicemente se self.role.idnon è un elenco di pacchetti:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)

1
Non sembra funzionare. Poiché self.role.id è solo un int e trigger_roles è un elenco di essi, avrei bisogno di un invertito in, come contiene ma, come ho scoperto, contiene è solo per le stringhe.
Grave_Jumper

8
Il secondo esempio dovrebbe funzionare. Se il valore in self.role.idè uno dei ruoli trigger, il filtro dovrebbe eseguire il pull di tutti i flussi di lavoro in cui uno dei ruoli trigger è il valore in self.role.id. Fondamentalmente questo si comporterà esattamente come una funzione "contiene". A meno che non ci manchi qualcosa.
Jordan Reiter

@Jordan Reiter: "contiene" viene convertito in sql in "mi piace" che non è quello che vuole l'OP e penso che lo abbia già sottolineato, d'altra parte "esatto" viene convertito in "=" o "è" che è il idea qui.
mouad

@Grave_Jumper: dai un'occhiata qui ( djangoproject.com/documentation/models/many_to_many ) puoi trovare qualche esempio quando lavori con ManytoMany Field, spero che questo possa aiutarti, se la mia risposta non è :)
mouad

1
aww .. scusa la tua seconda soluzione funziona abbastanza bene :) C'era un piccolo errore di configurazione dalla mia parte. Grazie ragazzi, questo mi ha salvato la giornata ;-)
Grave_Jumper

19

L'approccio più semplice per ottenere ciò sarebbe controllare l'uguaglianza sull'intera istanza (invece dell'id) nel file ManyToManyField. Quello sembra se l'istanza è all'interno della relazione molti a molti. Esempio:

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

7

So che questa è una vecchia domanda, ma sembra che l'OP non abbia mai ottenuto la risposta che stava cercando. Se hai due set di ManyToManyField che vuoi confrontare, il trucco è usare l' __inoperatore, no contains. Quindi, ad esempio, se hai un modello "Evento" con un campo ManyToMany in "Gruppo" eventgroupse il tuo modello utente (ovviamente) si collega a Gruppo, puoi eseguire una query in questo modo:

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


4

la singolarità è quasi giusta con il primo esempio. Devi solo assicurarti che sia un elenco. Il secondo esempio, controllando il trigger_roles__id__exactè una soluzione migliore però.

module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.