Django:过滤由联合体构成的查询集不起作用

Nas*_*gar 5 python django

我定义了3个与M2M关系有关的模型

class Suite(models.Model):
    name = models.CharField(max_length=250)
    title = models.CharField(max_length=250)
    icon = models.CharField(max_length=250)

    def __str__(self):
        return self.title



class Role(models.Model):
    name = models.CharField(max_length=250)
    title = models.CharField(max_length=250)
    suites = models.ManyToManyField(Suite)
    services = models.ManyToManyField(Service)
    Actions = models.ManyToManyField(Action)
    users = models.ManyToManyField(User)

    def __str__(self):
        return self.title
Run Code Online (Sandbox Code Playgroud)

在我的一种观点中,我试图收集与特定用户有关的所有Suite。用户可能与可能包含许多Suite的几个Role相关。然后按名称过滤Suite。但是过滤器似乎没有作用

queryset = Suite.objects.union(*(role.suites.all() for role in 
self.get_user().role_set.all()))
repr(self.queryset)

'<QuerySet [<Suite: energia>, <Suite: waste 4 thing>]>'

self.queryset = self.queryset.filter(name="energia")
repr(self.queryset)

'<QuerySet [<Suite: energia>, <Suite: waste 4 thing>]>'
Run Code Online (Sandbox Code Playgroud)

在执行过滤器之前,queryset内部的查询属性不会更改其内容:

(SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite") UNION (SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite" INNER JOIN "navbar_role_suites" ON ("navbar_suite"."id" = "navbar_role_suites"."suite_id") WHERE "navbar_role_suites"."role_id" = 1)

(SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite") UNION (SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite" INNER JOIN "navbar_role_suites" ON ("navbar_suite"."id" = "navbar_role_suites"."suite_id") WHERE "navbar_role_suites"."role_id" = 1)
Run Code Online (Sandbox Code Playgroud)

Gwy*_*idD 8

正如指出Django文档,只有count()order_by()values()values_list()和工会的查询集的切片是允许的。您无法根据联合查询集进行过滤。

这意味着,您必须在对查询应用联合之前对查询应用过滤器。

此外,您甚至无需使用即可实现目标union()

Suite.objects.filter(role_set__users=self.get_user(), name="energia")
Run Code Online (Sandbox Code Playgroud)

如果您已经使用过模型中的M2M字段related_namerelated_query_name定义了suitesM2M字段,则可能需要在过滤器中调整字段名称Role

  • 如果不允许,它应该真正引发一个异常,而不是像看起来那样默默地做什么。 (5认同)
  • 我遇到过的最糟糕的姜戈陷阱之一。 (4认同)
  • 哇!可怕的是,没有任何警告或错误表明不支持过滤并且将成为空操作。这让我很受伤。我感兴趣的是是否有任何不禁用过滤的替代方案。 (2认同)
  • 我打开了一个[错误跟踪器上的问题](https://code.djangoproject.com/ticket/30639)。 (2认同)

小智 8

我遇到了同样的问题,最终使用联合查询作为子查询,以便过滤器可以工作:

yourModelUnionSubQuerySet = YourModelQS1.union(YourModelQS2)
yourModelUnionQuerySet = YourModel.objects.filter(id__in=yourModelUnionSubQuerySet.values('id'))
Run Code Online (Sandbox Code Playgroud)


Rit*_*apa 5

有一个简单的解决方案。只需使用

self.queryset = self.queryset | <querySet you want to append>
Run Code Online (Sandbox Code Playgroud)

代替

self.queryset = self.queryset.union(<QuerySet you want to append>)
Run Code Online (Sandbox Code Playgroud)

为我工作。我希望这是可以理解的。之后您将能够使用过滤器。

  • 小心!这与使用 `.union` 不同!这让我很伤心,当你这样做时可能会出现非常奇怪的错误。它合并查询集,而不是“联合”它们。 (2认同)
  • 仅供参考 `|` 是“OR”运算符。它可能适用于某些用例,具体取决于某人想要做什么。它并不是真正“合并”查询集,正如我所描述的行为一样,它本质上是在输出 SQL 的“WHERE”部分添加了一个额外的“OR”。文档:https://docs.djangoproject.com/en/3.1/ref/models/querysets/#or (2认同)