Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 带倒Q对象的WHERE子句中的子查询_Python_Django_Postgresql_Orm - Fatal编程技术网

Python 带倒Q对象的WHERE子句中的子查询

Python 带倒Q对象的WHERE子句中的子查询,python,django,postgresql,orm,Python,Django,Postgresql,Orm,我有两个模型,其中一个是指另一个: class A(models.Model): variable = models.BooleanField(default=False, null=False) b = models.ForeignKey(B, on_delete=models.CASCADE, related_name='

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

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                                                                        
在对
变量进行筛选时,我想反向跟踪该关系:

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))'
'SELECT "b"."id" FROM "b" INNER JOIN "a" ON ("b"."id" = "a"."b_id") WHERE "a"."variable" = True'
另一方面,当不反转Q表达式时

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))'
'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
对象与
变量=True
相关”的否定不是查询“*所有
B
对象与
a
对象与
变量=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
对象,其中“存在一个相关的
a
对象,且
变量=True

但否定这一点的不是
B
对象列表”,其中存在一个相关的
a
对象,且
variable=False
(现在让我们忽略
NULL
花瓶)。实际上,一个
B
对象有两个相关的
a
对象,一个是
variable=True
,另一个是
variable=False
,它会出现在原始变量及其否定中

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

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

因此,这意味着对查询“存在
A
variable=True
的所有
B
对象”的否定是对查询“*所有相关
A
对象都有一个非
B
*的
变量的所有
B
对象”。请注意第二个查询中的all。因此,这意味着对于
A
表中的每一行,我们需要对相关的“B”对象进行“迭代”,以检查所有这些
变量
是否为
。这并不是真正为
JOIN
s“定制”的。在
布尔字段
的情况下,我们可以使用
GROUP BY
MAX(..)
来检查是否至少存在一个这样的
,从而约束它这不是
。比如:

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查询生成器进行一些“高级”平铺。这可能在将来的版本中最终会得到支持,但无论如何,效率将大致相同。

这是预期的行为。Django已经指定相关模型上的过滤器是使用存在量词完成的。存在量词的否定是带有否定谓词的通用量词。请参阅:对于您的情况,您可以使用
B.objects.filter(a_u变量=False)
(或者严格地说
B.objects.filter(Q(a_u变量=None)| Q(a_u变量=False))
,这与
B.objects.filter(Q(a_u变量=True))不同
但是将
a__变量=False
更改为
a__变量=True
应该与在Q表达式前面放置一个倒位相同。如果我遵循正向的引用,即
A.object.filter(Q(b_u-other_-var=True))
,为什么这会起作用呢?不,因为这会使它听起来不像“谓词逻辑”。假设有两个相关的
A
s,一个是
variable=True
,另一个是
variable=False
,您希望查询
B.objects.filter(~Q(A\u variable=True))
准确地包含查询
B.objects.filter(Q(A\u variable=True))
(因为您反转了条件),但是这里,
B
对象将出现在两个查询集中。