如何将DRF序列化结果按年份嵌套分组,重构响应格式?
如何调整DRF响应格式为指定结构?
问题概述
现有Transactions模型、利润统计视图及序列化器,当前返回的利润数据格式不符合需求,需要将month和profit字段嵌套到data对象中。
现有代码
模型
class Transactions(models.Model): id = models.CharField(max_length=100, primary_key=True) owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True) date = models.DateField() watch = models.CharField(max_length=100) purchase_price = models.IntegerField() sale_price = models.IntegerField()
视图
@api_view(['GET']) @permission_classes([IsAuthenticatedOrReadOnly]) def profit_chart(request): current_year = datetime.now().year queryset = Transactions.objects.filter(date__year=current_year).values(month=ExtractMonth('date'), year=ExtractYear('date')).annotate( profit=Sum(F('sale_price')) - Sum(F('purchase_price'))).order_by('month') serializer = ProfitChartSerializer(queryset, many=True) return Response(serializer.data, status=status.HTTP_200_OK)
序列化器
class ProfitChartSerializer(serializers.ModelSerializer): year = serializers.IntegerField() month = serializers.IntegerField() profit = serializers.IntegerField() class Meta: model = Transactions fields = ['year', 'month', 'profit']
当前响应格式
[ { "year": 2024, "month": 8, "profit": 5000 } ]
目标响应格式
[ { "year": 2024, "data": { "month": 8, "profit": 5000 } } ]
解决方案
方案1:修改序列化器(推荐)
通过嵌套序列化器重构字段结构,这是DRF处理数据格式的标准方式,代码更易维护:
- 定义嵌套序列化器处理
data字段:
class DataSerializer(serializers.Serializer): month = serializers.IntegerField() profit = serializers.IntegerField()
- 重写主序列化器,使用嵌套序列化器映射
data字段:
class ProfitChartSerializer(serializers.Serializer): year = serializers.IntegerField() data = DataSerializer(source='*') # source='*'将当前对象的所有数据传入嵌套序列化器 class Meta: fields = ['year', 'data']
注:将原
ModelSerializer改为Serializer,因为这里不需要模型默认字段映射,完全自定义结构更灵活。
方案2:视图中手动重构数据
如果不想修改序列化器,可在视图层对序列化后的结果进行结构调整:
@api_view(['GET']) @permission_classes([IsAuthenticatedOrReadOnly]) def profit_chart(request): current_year = datetime.now().year queryset = Transactions.objects.filter(date__year=current_year).values(month=ExtractMonth('date'), year=ExtractYear('date')).annotate( profit=Sum(F('sale_price')) - Sum(F('purchase_price'))).order_by('month') serializer = ProfitChartSerializer(queryset, many=True) # 重构数据结构 formatted_data = [ { "year": item["year"], "data": { "month": item["month"], "profit": item["profit"] } } for item in serializer.data ] return Response(formatted_data, status=status.HTTP_200_OK)
内容的提问来源于stack exchange,提问作者ElasticPanda
相关产品推荐
相关产品推荐

