110 votes

Filtre Django many-to-many avec contains

J'essaie de filtrer un ensemble d'objets à travers une relation de plusieurs à plusieurs. Comme la relation trigger_roles peut contenir plusieurs entrées, j'ai essayé l'option contains filtre. Mais comme ce filtre est conçu pour être utilisé avec des chaînes de caractères, je ne sais pas comment filtrer cette relation (vous pouvez ignorer l'élément values_list() atm.).

Cette fonction est rattachée au profil de l'utilisateur :

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)

Mon modèle de flux de travail se présente comme suit (simplifié) :

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)

Bien que la solution puisse être très simple, mon cerveau ne me le dit pas.

Merci pour votre aide.

135voto

mouad Points 21520

Avez-vous essayé quelque chose comme ceci :

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

ou simplement si self.role.id n'est pas une liste de pks :

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

27voto

Caumons Points 1702

L'approche la plus simple consisterait à vérifier l'égalité sur l'ensemble de l'instance (au lieu de l'identifiant) dans l'élément ManyToManyField . Cela permet de voir si l'instance se trouve dans la relation de plusieurs à plusieurs. Exemple :

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

9voto

shacker Points 3348

Je sais que c'est une vieille question, mais il semble que l'OP n'ait jamais obtenu la réponse qu'il cherchait. Si vous avez deux ensembles de ManyToManyFields que vous voulez comparer, l'astuce consiste à utiliser la méthode __in et non l'opérateur contains . Par exemple, si vous avez un modèle "Événement" avec un ManyToMany vers "Groupe" sur le champ eventgroups et que votre modèle User (évidemment) se rattache à Group, vous pouvez faire une requête comme suit :

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

7voto

Josh Smeaton Points 18165

Singularité a presque raison dans le premier exemple. Il suffit de s'assurer qu'il s'agit bien d'une liste. Dans le deuxième exemple, la vérification de la trigger_roles__id__exact est une meilleure solution.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X