【发布时间】:2019-01-29 16:23:39
【问题描述】:
我有两个模型,其中一个引用另一个:
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
【问题讨论】:
-
这是预期行为。 Django 已指定相关模型上的过滤器使用 existential 量词完成。存在量词的否定是带有否定谓词的全称量词。
-
对于您的情况,您可以使用
B.objects.filter(a__variable=False)(或者严格来说是B.objects.filter(Q(a__variable=None) | Q(a__variable=False))),这与B.objects.filter(Q(a__variable=True))不同 -
但是将
a__variable=False更改为a__variable=True应该与在Q 表达式前面放置一个反转相同。如果我按照正向参考,即A.object.filter(Q(b__another_var=True)),为什么这会起作用? -
不,因为这会使它与“谓词逻辑”不符。假设有两个相关的
As,一个与variable=True,一个与variable=False,您希望查询B.objects.filter(~Q(a__variable=True))恰好包含未 发生的Bs在查询B.objects.filter(Q(a___variable=True))中(因为您反转了条件),但这里B对象将出现在 both 查询集中。
标签: python django postgresql orm