过滤多对多字段Django

Posted

技术标签:

【中文标题】过滤多对多字段Django【英文标题】:Filtering many to many field Django 【发布时间】:2018-06-07 07:04:19 【问题描述】:

我有一个这样的查询:

    queryset = User.objects.filter(
            ~Q(pk=self.request.user.pk),
            ~Q(connections_as_initiator__peer=self.request.user, 
               connections_as_initiator__stopped=False))

在一个发起者和对等方之间可能有许多连接,但只有一个不是stopped。所以我想要这个查询做的是找出当前用户和被查询的用户之间是否存在当前用户是对等点的活动连接。但这根本不是发生的事情:

SELECT accounts_user.id FROM accounts_user
WHERE (
  NOT accounts_user.id = 48
  AND NOT accounts_user.id IN (SELECT U1.initiator_id AS col1 FROM connection U1 WHERE U1.peer_id = 48)
      AND NOT accounts_user.id IN (SELECT U1.initiator_id AS col1 FROM connection U1 WHERE U1.stopped = FALSE)
);

我在想什么(以及什么给出了预期的结果)是这样的:

SELECT accounts_user.id FROM accounts_user
WHERE (
  NOT accounts_user.id = 48
  AND NOT accounts_user.id IN (SELECT U1.initiator_id AS col1 FROM connection U1 WHERE U1.peer_id = 48 AND U1.stopped = FALSE)
);

有没有办法使用 ORM 来实现,或者我应该开始使用原始 SQL。我也在考虑注解,但我还不能 100% 确定如何以这种方式实现它。

【问题讨论】:

【参考方案1】:

看来我想出了一个解决方案。

queryset.annotate(
            initiated_conn_with_usr=Case(
                When(
                    connections_as_initiator__peer=self.request.user, 
                    connections_as_initiator__stopped=False, 
                    then=True
                ), default=False, output_field=models.BooleanField()
            )
        ).filter(initiated_conn_with_usr=True).distinct()

结果如下:

SELECT DISTINCT accounts_user.id,
  CASE WHEN (connection.peer_id = 48 AND connection.stopped = false)
    THEN true ELSE false END AS initiated_conn_with_usr FROM accounts_user
  LEFT OUTER JOIN connection ON (accounts_user.id = connection.initiator_id)
WHERE (CASE WHEN (connection.peer_id = 48 AND connection.stopped = false)
  THEN true ELSE false END = false);

可能不是最优化的变体,但至少它适用于一个请求。如果有更好的方法,请告诉我。

【讨论】:

以上是关于过滤多对多字段Django的主要内容,如果未能解决你的问题,请参考以下文章

Django 多对多字段过滤器列表

如何以 django 形式过滤多对多字段

过滤多对多字段Django

如何过滤和访问 Django QuerySet 中的多对多字段?

Django 查询集过滤具有相同多对多字段的对象

Django模板过滤2个多对多字段