子查询在带有倒置的Q对象的WHERE子句中

2024-04-24 23:02:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个模型,其中一个是指另一个:

class A(models.Model):                                                          

    variable = models.BooleanField(default=False, null=False)                   
    b = models.ForeignKey(B, on_delete=models.CASCADE, related_name='as', related_query_name="a") 


class B(models.Model):
    pass                                                                        

在对variable进行筛选时,我希望向后跟踪关系:

B.objects.filter(~Q(a__variable))

问题: 这将在where子句中产生一个额外的子查询:

'SELECT "b"."id" FROM "b" WHERE NOT ("b"."id" IN (SELECT U1."b_id" FROM "a" U1 WHERE U1."variable" = True))'

另一方面,当不反转Q表达式时

B.objects.filter(Q(a__variable))

联接是“正确”完成的,即在where子句之外:

'SELECT "b"."id" FROM "b" INNER JOIN "a" ON ("b"."id" = "a"."b_id") WHERE "a"."variable" = True'

注意:我只用布尔值作为例子(我可以把它变成False

我使用的是django 2.0.4和postgres 9.6.2


Tags: namefromidfalsemodelobjectsmodelsfilter
1条回答
网友
1楼 · 发布于 2024-04-24 23:02:41

简短回答:对“所有B对象与A对象与variable = True相关”的否定是而不是查询“*所有B对象与A对象与variable = False相关”。你知道吗

您可以这样查询:

B.objects.filter(a__variable=False)

或者,如果该字段是NULL-可以的:

B.objects.filter(Q(a__variable=None) | Q(a__variable=False))

背景:否定存在量化表达

这是预期的行为。因为如果你以一对多的方式查询一个与相关的模型,Django ORM的设计者选择了存在量词∃而不是通用量词∀。虽然我认为人类将执行的大多数查询都是存在的量化的,但没有内在的最佳选择。你知道吗

存在量词的意思是“存在”,所以如果你写B.objects.filter(a__variable=True),你要求B对象,其中“存在一个与variable=True相关的A对象”。你知道吗

但是这的否定不是B对象的列表,其中存在一个与variable=False相关的A对象(让我们暂时忽略NULL花瓶)。事实上,一个B对象有两个相关的A对象,一个有variable = True,一个有variable = False的对象会出现在原始变体和它的否定中。你知道吗

存在量化需求的否定,是该谓词否定的单一量化变体。或者在数学方面:

,∃x:p(x)↔ ∀x:P(x)

因此,这意味着查询“所有B对象存在一个Avariable=True”的否定是查询“*所有B对象,其所有相关A对象具有一个variable,即不是B*”。注意第二个查询中的all。因此,这意味着对于A表中的每一行,我们需要对相关的“B”对象进行“迭代”,以检查这些variable是否都是而不是True。这并不是真正为JOIN量身定做的。在BooleanField的情况下,我们可以用GROUP BYMAX(..)来检查是否至少有一个这样的TRUE存在,从而约束它这不是^{TRUE。比如:

SELECT b.*, MAX(a.variable) AS mx
FROM b
LEFT OUTER JOIN b ON a.b_id = b.id
GROUP BY a.id
HAVING mx = FALSE OR mx IS NULL

但是这个“技巧”需要Django ORM查询生成器进行一些“高级”平铺。这也许在将来的版本中最终会得到支持,但不管怎样,效率将大致相同。你知道吗

相关问题 更多 >