django ORM 将相关 table 上的两个条件转换为两个单独的 JOIN
django ORM turns two conditions on related table into two separate JOINs
我有这样的情况,我需要从相关 table.
中过滤两个属性
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_a
和 voucher_b
相关的项目,则找不到它,因为它在 JOIN 1 中但不在 JOIN 2 中。
它看起来像是 django 中的一个错误,但我无法在网上找到任何对这个主题有用的东西。
我们在 django==2.1.1
上并尝试将 exclude
切换为 filter
或使用 Q
表达式。到目前为止没有任何效果。
谢谢
罗恩
您的设置是一种 m2m 关系,您想要排除具有至少一个 m2m 关系且此 AND 条件组合为真的任何单个对象。
M2M 关系在 filter/exclude 查询集方面很特殊,请参阅 https://docs.djangoproject.com/en/2.1/topics/db/queries/#spanning-multi-valued-relationships
另请注意该文档:
The behavior of filter() for queries that span multi-value relationships, as described above, is not implemented equivalently for exclude(). Instead, the conditions in a single exclude() call will not necessarily refer to the same item.
文档中提供的解决方案如下:
Blog.objects.exclude(
entry__in=Entry.objects.filter(
headline__contains='Lennon',
pub_date__year=2008,
),
)
我有这样的情况,我需要从相关 table.
中过滤两个属性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_a
和 voucher_b
相关的项目,则找不到它,因为它在 JOIN 1 中但不在 JOIN 2 中。
它看起来像是 django 中的一个错误,但我无法在网上找到任何对这个主题有用的东西。
我们在 django==2.1.1
上并尝试将 exclude
切换为 filter
或使用 Q
表达式。到目前为止没有任何效果。
谢谢
罗恩
您的设置是一种 m2m 关系,您想要排除具有至少一个 m2m 关系且此 AND 条件组合为真的任何单个对象。
M2M 关系在 filter/exclude 查询集方面很特殊,请参阅 https://docs.djangoproject.com/en/2.1/topics/db/queries/#spanning-multi-valued-relationships
另请注意该文档:
The behavior of filter() for queries that span multi-value relationships, as described above, is not implemented equivalently for exclude(). Instead, the conditions in a single exclude() call will not necessarily refer to the same item.
文档中提供的解决方案如下:
Blog.objects.exclude(
entry__in=Entry.objects.filter(
headline__contains='Lennon',
pub_date__year=2008,
),
)