如果只需要更改 True / False 在 xlsx 中的显示方式 - 一种选择是只使用一个 related_exists BooleanField 注释,然后在创建 xlsx 文档时自定义它的转换方式 - 即在序列化程序中。数据库应存储原始/未格式化的值,并且应用程序准备将它们显示给用户。
其他需要考虑的事项:
- 用于加速过滤的索引。
- 如果您在过滤后有数百万条记录,则在一张表中 - 也许可以考虑进行表分区。
但是让我们看看原始查询的原始 sql。 会是这样的:
SELECT [model_fields],
EXISTS([CLIENT_SELECT]) AS related_exists,
CASE
WHEN EXISTS([CLIENT_SELECT]) = true THEN 'The relation exists!'
WHEN EXISTS([CLIENT_SELECT]) = true THEN 'The relation does not exist!'
ELSE 'The relation exists!'
END AS related_column
FROM model;
我们可以立即看到 Exists CLIENT_SELECT 的嵌套查询存在 3 次。即使完全一样,也可以执行最少 2 次,最多执行 3 次。数据库可能会将其优化为快于 3 倍,但仍不如 1 倍。
首先,EXISTS 返回 True 或 False,我们可以只检查它是否为 True,将 'The relation does not exist!' 设为默认值。
related_column=Case(
When(related_exists=True, then=Value('The relation exists!')),
default=Value('The relation does not exist!')
为什么related_column 再次执行相同的选择而不采用related_exists 的值?
因为我们在计算其他列时无法引用计算列 - 这是 django 知道并重复表达式的数据库级约束。
等等,那么我们实际上不需要related_exists 列,让related_column 留下CASE 语句并且1 存在子查询。
Django 来了——我们不能(直到 3.0)在过滤器中使用表达式而不先注释它们。
所以,我们的例子是这样的:为了在When中使用Exist,我们首先需要将它添加为注解,但它不会用作参考,而是表达式的完整副本.
好消息!
由于Django 3.0,我们可以在查询集过滤器中直接使用输出 BooleanField 的表达式,而无需先进行注释。 Exists 就是这样的 BooleaField 表达式之一。
Model.objects.all().annotate(
related_column=Case(
When(
Exists(RelatedModel.objects.filter(foreign_key_model=OuterRef('id'))),
then=Value('The relation exists!'),
),
default=Value('The relation doesn't exist!'),
output_field=CharField(),
)
)
只有一个嵌套选择和一个带注释的字段。
Django 2.1、2.2
这是commit,它最终确定了允许布尔表达式,尽管之前添加了许多前提条件。其中之一是表达式对象上存在conditional 属性并检查该属性。
因此,虽然 不推荐 和 未测试,但对于 Django 2.1、2.2 来说,这似乎很有效(在没有 conditional 检查之前,它需要更具侵入性的变化):
- 创建
Exists表达式实例
- 猴子用
conditional = True修补它
- 在
When 语句中将其用作条件
related_model_exists = Exists(RelatedModel.objects.filter(foreign_key_model=OuterRef('id')))
setattr(related_model_exists, 'conditional', True)
Model.objects.all().annotate(
related_column=Case(
When(
relate_model_exists,
then=Value('The relation exists!'),
),
default=Value('The relation doesn't exist!'),
output_field=CharField(),
)
)
相关检查
relatedmodel_set__isnull=True检查不适合以下几个原因:
- 它执行
LEFT OUTER JOIN - 效率低于EXISTS
- 它执行
LEFT OUTER JOIN - 它连接表,这使其仅适用于 filter() 条件(不适用于注释 - 何时),并且仅适用于 OneToOne 或 OneToMany(一个在相关模型端)关系