Django Rest Framework聚合后自定义字段返回及序列化问题
问题根因
- 核心逻辑错配:现有
TransactionSerializer是绑定Transactions模型的ModelSerializer,适配单条模型实例的字段结构,和当前聚合查询返回的字典集合(仅包含vendor、a、b三个自定义字段)完全不匹配。 - 序列化报错来源:聚合生成的
b字段是Sum(amount)的计算结果,类型为Decimal,没有对应序列化规则的情况下会触发类型不兼容报错。
实现步骤
1. 新建适配聚合结果的序列化器
不要复用原有绑定模型的TransactionSerializer,在serializer.py中新增专门处理聚合结果的序列化类,明确声明每个字段的类型,同时用DRF自带的DecimalField处理Decimal类型的聚合值,从根源解决序列化问题:
from rest_framework import serializers class SmartStatsSerializer(serializers.Serializer): # 对应values查询中的vendor字段 vendor = serializers.CharField() # 对应annotate中Count生成的a字段 a = serializers.IntegerField() # 对应annotate中Sum生成的b字段,直接用DecimalField适配数值类型 b = serializers.DecimalField(max_digits=19, decimal_places=2)
此处使用基础
Serializer而非ModelSerializer,因为聚合结果不绑定具体模型实例,无需走模型字段自动映射逻辑。
2. 修改视图类的序列化器绑定
把视图类中原有绑定的TransactionSerializer替换为新建的聚合结果序列化器:
class smarts(generics.ListAPIView): # 替换为适配聚合结果的序列化器 serializer_class = SmartStatsSerializer permission_classes = [permissions.IsAuthenticated, TransactionIsOwnerOrNot]
3. 完善get_queryset的返回逻辑
你之前编写的聚合查询本身逻辑正确,不需要额外做手动JSON编码处理,直接返回该查询集即可——DRF的ListAPIView会自动将查询集(包括.values()生成的字典集合)传给绑定的序列化器完成序列化,最终输出符合要求的JSON响应:
def get_queryset(self): card = get_object_or_404(self.request.user.cards, pk=self.kwargs['pk']) # 聚合查询逻辑保持原有实现不变 qs = card.transactions.values('vendor').annotate( a=Count('pk'), b=Sum('amount') ).order_by('-b') # 直接返回构造好的查询集即可 return qs
注意事项
- 无需额外手动调用
DjangoJSONEncoder,DRF序列化器已内置对Decimal类型的完整支持,只要匹配对应字段类型,即可正常序列化输出。 - 不推荐直接修改原有
TransactionSerializer的字段定义来适配聚合需求,会导致原有绑定模型的序列化器被污染,影响其他使用该序列化器的接口功能。
内容的提问来源于stack exchange,提问作者Aditya Mahajan
相关产品推荐
相关产品推荐

