【问题标题】:Use annotate and Case with different field types in Django在 Django 中使用具有不同字段类型的 annotate 和 Case
【发布时间】:2018-07-25 11:41:15
【问题描述】:

我有一个具有这些领域的模型:

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

【问题讨论】:

  • 看起来很不安全。为什么text_codeCharField如果是数字?
  • @WillemVanOnsem 这个字段来自另一个类,它可以是数字或文本,具体取决于模型
  • @WillemVanOnsem 非常感谢!我花了两天时间阅读文档,并没有看到那个功能!

标签: python django postgresql django-annotate


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2015-08-22
    • 2019-04-06
    • 2021-01-30
    • 2011-06-21
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    相关资源
    最近更新 更多