Django filter many-to-many with contains

Question:

I am trying to filter a bunch of objects through a many-to-many relation. Because the trigger_roles field may contain multiple entries I tried the contains filter. But as that is designed to be used with strings I’m pretty much helpless how i should filter this relation (you can ignore the values_list() atm.).

This function is attached to the user profile:

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)

My workflow model looks like this (simplified):

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)

Though the solution might be quiet simple, my brain won’t tell me.

Thanks for your help.

Asked By: Grave_Jumper

||

Answers:

Have you tried something like this:

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

or just if self.role.id is not a list of pks:

module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)
Answered By: mouad

singularity is almost right with the first example. You just need to make sure it’s a list. The second example, checking the trigger_roles__id__exact is a better solution though.

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

The simplest approach to achieve this would be checking for equalty over the whole instance (instead of the id) in the ManyToManyField. That looks if the instance is inside the many to many relationship. Example:

module.workflow_set.filter(trigger_roles=self.role, allowed=True)
Answered By: Caumons

I know this is an old question, but it looks like the OP never quite got the answer he was looking for. If you have two sets of ManyToManyFields you want to compare, the trick is to use the __in operator, not contains. So for example if you have an “Event” model with a ManyToMany to “Group” on field eventgroups, and your User model (obviously) attaches to Group, you can query like this:

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

Answered By: shacker