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

Django QuerySet转列表annotate的Decimal字段JSON序列化异常修复

问题根因

你的判断完全正确,问题出在Decimal类型的JSON序列化兼容上。
Django的Sum聚合函数在处理数值字段时默认返回Decimal类型,而Python标准库自带的JSON序列化器不支持该类型,序列化过程中无法正常转换就会直接输出null,就会出现终端打印queryset值正常、前端拿到的combined_quantity为空的现象。

可行解决方法

你可以根据自己的业务场景选下面任意一种方案:

方案1:查询阶段直接转成浮点型(改动最小,快速生效)

用Django内置的Cast函数,在ORM查询时就把Sum结果转换为浮点类型,查出来的结果直接是普通float值,不需要额外调整序列化逻辑:
首先导入依赖:

from django.db.models import FloatField
from django.db.models.functions import Cast

修改原有查询语句,给Sum计算套上类型转换:

queryset = list(
    Products.objects.filter(status=True, salelog__created__range=(start, today))
    .values("name")
    .annotate(individual_sales=Count("salelog__quantity"))
    .annotate(combined_quantity=Cast(Sum("salelog__quantity"), output_field=FloatField()))
)

改完直接用原有JsonResponse返回即可,前端拿到的就是标准数字类型。
注意:浮点类型存在二进制精度丢失问题,如果你的业务是金额类对精度要求极高,不要用这个方案,选后面两种。

方案2:指定支持Decimal的JSON编码器(通用方案,无精度损失)

不需要修改ORM查询逻辑,只需要在返回响应时指定支持Decimal类型的JSON编码器即可。
Django本身自带了支持Decimal、datetime、UUID等特殊类型的编码器DjangoJSONEncoder,不需要自己写代码,直接引入使用就行:

from django.http import JsonResponse
from django.core.serializers.json import DjangoJSONEncoder

# 原有查询逻辑完全不变
return JsonResponse(queryset, safe=False, encoder=DjangoJSONEncoder)

这个自带编码器默认会把Decimal转成字符串返回,完全不会丢失精度。如果需要直接返回数字类型,也可以自己写个简单的编码器:

import json
from decimal import Decimal

class CustomDecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj) # 要无精度损失就返回str(obj)
        return super().default(obj)

返回时把encoder参数换成你自己写的CustomDecimalEncoder即可。
如果项目里大量接口都要处理Decimal类型,可以去settings.py里配置全局默认的JSON编码器,不用每次写接口都传encoder参数。

方案3:用DRF序列化器(集成了DRF的项目推荐用)

如果你的项目已经用了Django REST Framework,直接定义对应序列化类处理字段类型即可,DRF自带的DecimalField支持灵活配置返回格式、精度校验:

from rest_framework import serializers

class SalesStatsSerializer(serializers.Serializer):
    name = serializers.CharField()
    individual_sales = serializers.IntegerField()
    # coerce_to_string=False返回数字类型,True返回字符串类型
    combined_quantity = serializers.DecimalField(max_digits=10, decimal_places=2, coerce_to_string=False)

查询完成后用序列化器做转换再返回:

from rest_framework.response import Response

serializer = SalesStatsSerializer(queryset, many=True)
return Response(serializer.data)
前端注意点

如果你选择把Decimal转成字符串返回,Vue侧做数值计算前先用Number(val)或者parseFloat(val)做一次类型转换,避免出现字符串拼接的错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:36:24