我有两个模型,其中一个是指另一个:
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
简短回答:对“所有
B
对象与A
对象与variable = True
相关”的否定是而不是查询“*所有B
对象与A
对象与variable = False
相关”。你知道吗您可以这样查询:
或者,如果该字段是
NULL
-可以的:背景:否定存在量化表达
这是预期的行为。因为如果你以一对多的方式查询一个与相关的模型,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
对象存在一个A
且variable=True
”的否定是查询“*所有B
对象,其所有相关A
对象具有一个variable
,即不是B
*”。注意第二个查询中的all。因此,这意味着对于A
表中的每一行,我们需要对相关的“B”对象进行“迭代”,以检查这些variable
是否都是而不是True
。这并不是真正为JOIN
量身定做的。在BooleanField
的情况下,我们可以用GROUP BY
和MAX(..)
来检查是否至少有一个这样的TRUE
存在,从而约束它这不是^{TRUE
。比如:但是这个“技巧”需要Django ORM查询生成器进行一些“高级”平铺。这也许在将来的版本中最终会得到支持,但不管怎样,效率将大致相同。你知道吗
相关问题 更多 >
编程相关推荐