【问题标题】:django ORM turns two conditions on related table into two separate JOINsdjango ORM 将相关表上的两个条件转换为两个单独的 JOIN
【发布时间】:2018-09-21 08:44:36
【问题描述】:

我需要过滤相关表中的两个属性。

class Item(models.Model):
     vouchers = models.ManyToManyField()


class Voucher(models.Model):
     is_active = models.BooleanField()
     status = models.PositiveIntegerField()

当我这样查询 ORM 时:

Item.objects.exclude(
    vouchers__is_active=False, 
    vouchers__status__in=[1, 2])      

创建的查询如下所示:

SELECT *
FROM `item`
WHERE NOT (`item`.`id` IN (
   SELECT U1.`item_id`
   FROM `itemvouchers` U1
   INNER JOIN `voucher` U2 ON (U1.`voucher_id` = U2.`id`)
   WHERE U2.`is_active` = FALSE) 
 AND 
`item`.`id` IN (
   SELECT U1.`item_id`
   FROM `itemvouchers` U1
   INNER JOIN `voucher` U2 ON (U1.`voucher_id` = U2.`id`)
   WHERE U2.`status` IN (1, 2))
)

我想排除处于非活动状态且状态为 1 或 2 的凭证。

查询所做的是创建两个单独的连接。这起初是不必要的,而且对性能不利。其次,这是错误的。

案例:

voucher_a = Voucher.objects.create(status=3, is_active=True)
voucher_b = Voucher.objects.create(status=1, is_active=False)

如果我有一个与 voucher_avoucher_b 相关的项目,则找不到它,因为它在 JOIN 1 中但不在 JOIN 2 中。

这看起来像是 django 中的一个错误,但我无法在网络上找到任何对这个主题有用的东西。

我们正在使用django==2.1.1 并尝试使用filter 或使用Q-表达式切换exclude。到目前为止没有任何效果。

谢谢

罗恩

【问题讨论】:

  • 不,这不是错误。由于.filter(..)存在量化的,.exists(..) 应该*普遍地量化,因此行为。
  • 抱歉,没明白你的意思。您能否详细说明一下。此外:您有解决方案吗?

标签: django join django-orm


【解决方案1】:

您的设置是一个 m2m 关系,并且您希望排除任何具有至少一个 m2m 关系且此 AND 条件组合为真的单个对象。

M2M 关系在过滤/排除查询集方面是特殊的,请参阅 https://docs.djangoproject.com/en/2.1/topics/db/queries/#spanning-multi-valued-relationships

还要在该文档中注明:

如上所述,对于跨越多值关系的查询,filter() 的行为并不等同于 exclude()。相反,单个 exclude() 调用中的条件不一定引用同一个项目。

文档中提出的解决方案如下:

Blog.objects.exclude(
    entry__in=Entry.objects.filter(
        headline__contains='Lennon',
        pub_date__year=2008,
    ),
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 2022-06-19
    • 2017-06-12
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    相关资源
    最近更新 更多