首页 > 解决方案 > 在 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)

我想使用带有这些规则的注释和案例对该模型进行查询:

我可以使用 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

标签: pythondjangopostgresqldjango-annotate

解决方案


答案是,使用 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(),
    ),
)

推荐阅读