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
相关产品推荐
相关产品推荐

