django - 如何将 Django 查询过滤器放在 ON 子句而不是 WHERE 子句中?
问题描述
在 SQL 中,条件的放置,无论是在 ON 子句还是 WHERE 子句中,都会影响结果。filter()
在 Django 中似乎将条件放在 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 子句中?
解决方案
自 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
推荐阅读
- python - 视频到 ASCII 转换器——优化
- laravel - 是否可以在 firstOrNew、firstOrCreate、updateOrCreate 上使用 WhereIn / WhereNull 或 Condition?
- swiftui - 如何将 String?-type 对象分配给 String-type 变量?
- ruby-on-rails - RSpec - 无法模拟 ActiveRecord 模型类
- tags - 找不到模块:无法解析“react-meta-tags”
- javascript - 图像不会使用这些脚本调整大小
- jquery - 更改事件不适用于使用 jquery 的 span 标签
- visual-studio-code - 启动 VS Code 时重新定义终端不起作用
- interface - 在 Open Modelica 中定义 Medium 后仍然存在介质问题
- java - 保护本地 Java 嵌入式数据库