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

如何修改Django序列化器输出,按项目分组合同数据?

Django序列化器按项目分组输出的实现方案

问题描述

我想要修改Django序列化器的输出格式。基于类的视图中有get_projects方法,它返回Contract实例的queryset:

projects = Project.objects.all()
contracts = Contract.objects.filter(project__in=projects)

Contract与Project是一对多关系:

class Contract(models.Model):
    project = models.ForeignKey(Project)

当前使用的MySerializer如下:

class MySerializer(serializers.Serializer):
    project_guid = serializers.UUIDField(source='guid')
    project_name = serializers.CharField(source='name')
    contract_guid = serializers.UUIDField(source='guid')
    contract_number = serializers.CharField(source='number')

该序列化器的输出为:

[
  {
    "projectGuid": "project_guid_1",
    "projectName": "project_name_1",
    "contractGuid": "contract_guid_1",
    "contractNumber": "contract_number_1"
  },
  {
    "projectGuid": "project_guid_1",
    "projectName": "project_name_1",
    "contractGuid": "contract_guid_2",
    "contractNumber": "contract_number_2"
  },
  {
    "projectGuid": "project_guid_2",
    "projectName": "project_name_2",
    "contractGuid": "contract_guid_4",
    "contractNumber": "contract_number_4"
  },
  {
    "projectGuid": "project_guid_2",
    "projectName": "project_name_2",
    "contractGuid": "contract_guid_5",
    "contractNumber": "contract_number_5"
  }
]

希望将输出修改为按项目分组合同的格式,示例如下:

[
 {
  "project_guid": "project_guid_1",
  "project_name": "project_name_1",
  "contracts": [
    {
      "contract_guid": "contract_guid_1",
      "contract_number": "contract_number_1"
    },
    {
      "contract_guid": "contract_guid_2",
      "contract_number": "contract_number_2"
    }
  ]
 },
 {
  "project_guid": "project_guid_2",
  "project_name": "project_name_2",
  "contracts": [
    {
      "contract_guid": "contract_guid_4",
      "contract_number": "contract_number_4"
    },
    {
      "contract_guid": "contract_guid_5",
      "contract_number": "contract_number_5"
    }
  ]
 }
]

请问如何实现这一需求?

解决方案

可以通过嵌套序列化器+优化查询逻辑的方式实现,步骤如下:

1. 定义合同子序列化器

先创建仅处理合同字段的序列化器,用于嵌套展示:

class ContractSerializer(serializers.Serializer):
    contract_guid = serializers.UUIDField(source='guid')
    contract_number = serializers.CharField(source='number')

2. 定义项目主序列化器

创建处理项目信息的序列化器,通过SerializerMethodField获取并序列化当前项目的所有合同:

class ProjectSerializer(serializers.Serializer):
    project_guid = serializers.UUIDField(source='guid')
    project_name = serializers.CharField(source='name')
    contracts = serializers.SerializerMethodField()

    def get_contracts(self, obj):
        # 从项目对象反向关联获取所有合同
        contracts = obj.contract_set.all()
        return ContractSerializer(contracts, many=True).data

3. 调整视图查询逻辑

将查询起点从合同改为项目,同时用prefetch_related预加载关联合同,避免N+1查询问题:

# 替换原有的contracts查询,改用预加载合同的项目queryset
projects = Project.objects.all().prefetch_related('contract_set')

4. 使用项目序列化器输出

在视图中用ProjectSerializer处理项目queryset,返回序列化后的数据:

serializer = ProjectSerializer(projects, many=True)
return Response(serializer.data)

可选:用ModelSerializer简化代码

如果模型字段与输出字段匹配度高,可使用ModelSerializer减少重复代码:

class ContractSerializer(serializers.ModelSerializer):
    class Meta:
        model = Contract
        fields = ['guid', 'number']
        extra_kwargs = {
            'guid': {'label': 'contract_guid'},
            'number': {'label': 'contract_number'}
        }

class ProjectSerializer(serializers.ModelSerializer):
    contracts = ContractSerializer(many=True, source='contract_set')
    
    class Meta:
        model = Project
        fields = ['guid', 'name', 'contracts']
        extra_kwargs = {
            'guid': {'label': 'project_guid'},
            'name': {'label': 'project_name'}
        }

这样就能得到按项目分组的目标输出格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:35:04