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

如何将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处理数据格式的标准方式,代码更易维护:

  1. 定义嵌套序列化器处理data字段:
class DataSerializer(serializers.Serializer):
    month = serializers.IntegerField()
    profit = serializers.IntegerField()
  1. 重写主序列化器,使用嵌套序列化器映射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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:53:11