在Django中对不同的字段类型使用注释和大小写

时间:2018-07-25 11:41:16

标签: python django postgresql django-annotate

我有一个具有这些字段的模型:

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)

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

  • 当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

1 个答案:

答案 0 :(得分:2)

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