在SQL中,条件的放置(无论是在ON子句中还是WHERE子句中)都会影响结果。 Django中的filter()
似乎将条件放在WHERE子句中。
说我有这些模型:
class Nations(models.Model):
deleted = models.BooleanField(default=False)
class People(models.Model):
nation = models.ForeignKey(Nations, on_delete=models.CASCADE)
deleted = models.BooleanField(default=False)
我想找到没有人的国家,我可以这样做:
SELECT nations.id, nations.deleted
FROM nations
LEFT JOIN people
ON people.nation_id = nations.id
WHERE people.id IS NULL;
但是,可以说人们可以被软删除,我想找到其中没有不败之民的国家。我会的:
SELECT nations.id, nations.deleted
FROM nations
LEFT JOIN people
ON people.nation_id = nations.id
AND people.deleted IS FALSE
WHERE people.id IS NULL;
但是,在Django中,如果我这样做:
Nations.objects.filter(people__id__isnull=True, people__deleted=False)
这等同于查询:
SELECT nations.id, nations.deleted
FROM nations
LEFT JOIN people
ON people.nation_id = nations.id
WHERE people.id IS NULL
AND people.deleted IS FALSE;
与所需查询不同,该查询将不包括仅删除人员的国家!如何让Django将软删除检查移到ON子句中?
答案 0 :(得分:3)
自Django 2.0以来,有一个鲜为人知的功能,名为FilteredRelation
,该功能允许向关系中添加其他过滤器。结果是联接的ON
子句中的附加条件:
nations = (Nations.objects
.annotate(no_deleted=FilteredRelation(
'people',
condition=Q(people__deleted=False)))
.filter(no_deleted=None)
)
print(str(nations.query))
生成的SQL看起来很像您所追求的:
SELECT "app_nations"."id",
"app_nations"....
FROM "app_nations"
LEFT OUTER JOIN "app_people" no_deleted ON
("app_nations"."id" = no_deleted."nations_id"
AND (no_deleted."deleted" = FALSE))
WHERE no_deleted."id" IS NULL
答案 1 :(得分:0)
在阅读您的最后一句话时,您似乎想要包括没有人的国家和只有被删除的人的国家。要做到这一点,您只需exclude那些没有删除人员的国家即可:
qs = Nations.objects.exclude(people__deleted=False)