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

如何在Django中聚合JSONField里amount字段的总和?

Django JSONField 数值聚合问题

我定义了如下Django模型,包含simple_json和nested_json两个JSONField字段,分别存储含amount键的简单JSON和嵌套JSON:

from django.db import models
import random

def simple_json_callable():
    return {"amount": random.randint(1, 100)}

def nested_json_callable():
    data = {
        "l1": {
            "l2": {
                "l3": {
                    "amount": random.randint(1, 100)
                }
            }
        }
    }
    return data

class Foo(models.Model):
    simple_json = models.JSONField(default=simple_json_callable)
    nested_json = models.JSONField(default=nested_json_callable)

我想要计算这两个字段中amount键对应值的总和,尝试了两种查询方式:

尝试的查询方式

方式1:先注解再聚合

result = Foo.objects.annotate(
    simple_json_amount=Cast('simple_json__amount', output_field=models.IntegerField()),
    nested_json_amount=Cast('nested_json__l1__l2__l3__amount', output_field=models.IntegerField()),
).aggregate(
    simple_json_total=models.Sum('simple_json_amount'),
    nested_json_total=models.Sum('nested_json_amount'),
)

方式2:直接聚合

result = Foo.objects.aggregate(
    simple_json_total=models.Sum(Cast('simple_json__amount', output_field=models.IntegerField())),
    nested_json_total=models.Sum(Cast('nested_json__l1__l2__l3__amount', output_field=models.IntegerField())),
)

但两种方式都报错:

django.db.utils.DataError: cannot cast jsonb object to type integer

请问在Django中,正确聚合JSONField中数值总和的方法是什么?


版本信息

  • Django 3.1.X
  • Python 3.9.X

正确解法

报错原因是直接使用simple_json__amount这类点式访问在Cast中时,Django ORM没有正确解析为JSON字段的键提取,反而错误地将整个JSON对象尝试转换为整数,触发数据库报错。

在Django 3.1中,需要使用KeyTransform函数明确提取JSON字段中的指定键值,再进行类型转换和聚合:

from django.db import models
from django.db.models.functions import KeyTransform

# 计算两个JSON字段中amount的总和
result = Foo.objects.aggregate(
    # 提取simple_json中的amount,转整数后求和
    simple_json_total=models.Sum(
        models.Cast(KeyTransform('amount', 'simple_json'), output_field=models.IntegerField())
    ),
    # 逐层提取嵌套JSON中的amount,转整数后求和
    nested_json_total=models.Sum(
        models.Cast(
            KeyTransform('amount', 
                KeyTransform('l3', 
                    KeyTransform('l2', 
                        KeyTransform('l1', 'nested_json')
                    )
                )
            ),
            output_field=models.IntegerField()
        )
    )
)

补充说明

  • KeyTransform用于从JSONField中提取指定键对应的值,嵌套结构需要逐层调用,每层对应一个JSON层级的键。
  • JSON存储的数值在数据库中是jsonb类型,必须通过Cast明确转换为IntegerField后,才能使用Sum进行聚合计算。
  • 该方案适配PostgreSQL数据库(报错信息显示使用的是jsonb类型,对应PostgreSQL)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:05:01