python - 在 Django 中使用具有不同字段类型的 annotate 和 Case
问题描述
我有这些领域的模型:
class ModelA(models.Model):
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.PROTECT, related_name='child')
number = models.PositiveIntegerField()
text_code = models.CharField(max_length=255, blank=True, null=True)
我想使用带有这些规则的注释和案例对该模型进行查询:
- 当 parent 为 null 时,它返回 text_code 字段
- 当 parent 不为 null 时,它返回 parent__number 字段
我可以使用 PostgreSQL 中的 SQL 来实现,例如:
CASE WHEN "ModelA"."parent_id" IS NOT NULL
THEN T3."number"**::integer**
ELSE "ModelA"."text_code"**::integer** END AS "control_field"
但我不能用 Django ORM 做到这一点。我尝试了以下方法:
query = ModelA.objects.all().select_related('parent').annotate(
control_field=Case(
When(parent_id__isnull=False, then='parent__number'),
default='text_code',
output_field=IntegerField(),
),
)
但是当我调用查询结果时,它会引发以下错误:
django.db.utils.ProgrammingError:CASE 类型字符不同且整数无法匹配
我知道这是一个数据库错误,因为 django 构造的 SQL 结果没有::integer添加。
CASE WHEN "ModelA"."parent_id" IS NOT NULL
THEN T3."number"
ELSE "ModelA"."text_code" END AS "control_field"
我该如何解决这个问题?我正在使用 Django 1.11
解决方案
答案是,使用 Cast:
query = ModelA.objects.all().select_related('parent').annotate(
control_field=Case(
When(parent_id__isnull=False, then=Cast('parent__number', IntegerField())),
default=Cast('text_code', IntegerField()),
output_field=IntegerField(),
),
)
推荐阅读
- iframe - 在 IE11 上的 ms-word 插件中获取“HTTPS 安全性受到威胁”
- c++ - C++ - memcpy 给出异常:std::bad_alloc
- java - 为什么 Kubernetes 中的 Java Container 需要更多的内存作为限制?
- r - Julia中回归系数的不同标准误差
- apache-spark - 使用火花逐位比较数据框中的两列
- javascript - 在 Javascript 表单中输入扩展拉丁字符 Alt+0256-0383
- c++ - 创建一个打开文件并使用 ifstream 和 ofstream 读取文件的函数,但它的 QT 说我没有声明该函数
- azure - 如何将 Azure App Service 应用程序设置加载到 VUE 中?
- python - lmfit 适合具有多个峰值的数据中的“错误”峰值
- python - chdir 函数不适用于 discord.py cog 的相对路径