You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django升级后annotate中Sum与Case组合使用报错求助

Django 4.1.2升级后Sum+Case查询报错问题解析

环境变化

  • 原环境:Python 3.8 + Django 1.12 + PostgreSQL 15(运行正常)
  • 新环境:Python 3.11 + Django 4.1.2 + PostgreSQL 15(报错)

相关代码

models.py

class TrackReport(BaseMixin):
    value = models.PositiveIntegerField()
    archive = models.ForeignKey("Archive", related_name="track_reports", on_delete=models.PROTECT)
    date = models.DateField(db_index=True)

查询语句

qs = Archive.objects
qs = qs.annotate(
                filtered_by_date_min=Sum(
                    Case(When(track_reports__date__gte=date_min, then=Value(1)), default=Value(0), output_field=IntegerField())
                )
            ).filter(filtered_by_date_min__gt=0)

报错信息

../../mambaforge/envs/new_sponsordata_arm/lib/python3.11/site-packages/django/db/models/sql/query.py:1289: in build_lookup
    lookup_class = lhs.get_lookup(lookup_name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Sum(CASE WHEN <WhereNode: (AND: In(Col(archive_trackreport, archive.TrackReport.type), ['FACEBOOK_POPULARITY']))> THEN Value(1), ELSE Value(0))
lookup = 'gt'

    def get_lookup(self, lookup):
>       return self.output_field.get_lookup(lookup)
E       AttributeError: 'IntegerField' object has no attribute 'get_lookup'

../../mambaforge/envs/new_sponsordata_arm/lib/python3.11/site-packages/django/db/models/expressions.py:377: AttributeError

问题原因

Django版本升级后,聚合函数与条件表达式的类型处理机制发生了变化:

  • 在Django 1.12中,Case表达式的output_field参数传入字段实例(IntegerField())可以被Sum聚合正确识别;
  • 但在Django 4.1.2中,Sum聚合后的表达式在处理__gt这类lookup时,会尝试调用output_field的get_lookup方法,而字段实例不再提供该方法(该方法现在归属于字段类或表达式内部逻辑),从而触发AttributeError。

解决方案

有两种可行的修改方式:

方式1:移除Case中的output_field参数

由于then和default的值都是整数类型(Value(1)、Value(0)),Django可以自动推断出字段类型,无需显式指定:

qs = Archive.objects.annotate(
    filtered_by_date_min=Sum(
        Case(When(track_reports__date__gte=date_min, then=Value(1)), default=Value(0))
    )
).filter(filtered_by_date_min__gt=0)

方式2:将output_field参数移到Sum聚合中

显式为Sum指定输出字段类型,替代Case中的设置:

qs = Archive.objects.annotate(
    filtered_by_date_min=Sum(
        Case(When(track_reports__date__gte=date_min, then=Value(1)), default=Value(0)),
        output_field=IntegerField()
    )
).filter(filtered_by_date_min__gt=0)

内容的提问来源于stack exchange,提问作者jnowak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 05:35:10