Django中使用contains过滤多对多关系

112

我正在尝试通过多对多关系过滤一堆对象。因为trigger_roles字段可能包含多个条目,所以我尝试使用contains过滤器。但是,由于它被设计用于字符串,我几乎无法确定如何过滤这个关系(您可以暂时忽略values_list())。

这个函数附加在用户资料上:

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)

我的工作流模型长这样(简化版):

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)

虽然解决方案可能很简单,但我的大脑没告诉我。

谢谢你的帮助。

4个回答

136

你尝试过像这样的东西吗:

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

或者只需检查self.role.id是否不是主键列表:

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

2
似乎不起作用。由于self.role.id只是一个整数,而trigger_roles是它们的列表,我需要一个反向的in,就像包含一样,但是我已经发现,contains仅适用于字符串。 - Grave_Jumper
9
第二个示例应该有效。如果self.role.id中的值是触发器角色之一,则该筛选器应该检索所有工作流,在这些工作流中,触发器角色之一是self.role.id中的值。基本上,这将表现得像一个“包含”函数。除非我们都漏掉了什么。 - Jordan Reiter
1
啊哦,很抱歉你的第二个解决方案非常有效 :) 这是我这边的一个小配置问题。谢谢大家,这救了我的一天;-) - Grave_Jumper
虽然有点混淆,但 module.workflow_set.filter(trigger_roles=self) 是正确的方法。 - Paul Whipp
1
@SeanLetendre:这是应用的过滤器之一(请参见示例中“Workflow”模型上的“allowed”属性)。它在没有上下文的情况下毫无意义。 - Sasha Chedygov
显示剩余3条评论

27

最简单的方法是在ManyToManyField中检查整个实例(而不是id)是否相等。这样做可以查看实例是否在多对多关系中。例如:

最简单的方法是在ManyToManyField中检查整个实例(而不是id)是否相等。这样做可以查看实例是否在多对多关系中。例如:

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

10

我知道这是一个老问题,但看起来提问者并没有得到他想要的答案。如果你有两组需要比较的ManyToManyFields,诀窍是使用 __in 运算符,而不是 contains。例如,如果你有一个“Event”模型,其中 “eventgroups” 字段与 “Group” 有 ManyToMany 关系,并且你的用户模型(显然)附加到 Group,可以像这样查询:

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


7

singularity几乎正确地处理了第一个示例。您只需要确保它是一个列表。不过,检查trigger_roles__id__exact是更好的解决方案。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接