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

Django Rest Framework中遍历带嵌套键的form-data数据方法

处理DRF中Form-Data嵌套数据的访问问题

问题背景

我在使用Django Rest Framework开发项目,需通过form-data提交文档创建企业。当前request.data的格式如下:

{
    'company[company_owner][email]': ['rohansheryabraham@gmail.com'],
    'company[company_owner][phone]': ['098765439'],
    'company[company_owner][first_name]': ['Mike'],
    'company[company_owner][last_name]': ['Tyson'],
    'company[company_name]': ['Testing'],
    'company[company_email]': ['testing@mail.com'],
    'company[company_mobile_phone]': ['980765432'],
    'company[company_landline]': ['78765421'],
    'company[company_country]': ['India'],
    'company[email_otp]': ['783143'],
    'company[mobile_otp]': ['256310'],
    'company_detail[0][detail]': ['110'],
    'company_details[0][documents]': [
        '<InMemoryUploadedFile: Screenshot from 2023-11-27 11-50-29.png (image/png)>','<InMemoryUploadedFile: Screenshot from 2023-11-27 11-50-20.png (image/png)>'
    ]
}

与JSON格式不同,无法直接通过company_detail[0]['documents']这种方式访问嵌套数据,当前视图仅能打印原始数据:

@api_view(['POST'])
@permission_classes([AllowAny])
@parser_classes([FormParser, MultiPartParser])
def test(request):
    print(request.data)
    # logic to create company
    return Response()

解决方案

方案1:手动解析为嵌套字典

编写一个工具函数,将扁平的form-data键值对转换为嵌套的字典/列表结构,支持处理带括号的键名:

def parse_form_data(data):
    result = {}
    for key, value in data.items():
        # 处理form-data的列表值:单值取第一个元素,多文件保留列表
        if isinstance(value, list):
            if len(value) == 1 and not isinstance(value[0], type(data['company_details[0][documents]'][0])):
                value = value[0]
        
        # 拆分键的层级,比如"company[company_owner][email]"拆分为["company", "company_owner", "email"]
        key_parts = key.replace('[', ']').split(']')
        key_parts = [part for part in key_parts if part]
        
        current_level = result
        for idx, part in enumerate(key_parts):
            # 处理索引类型的键(如"0")
            if part.isdigit():
                part = int(part)
                # 初始化列表(如果当前层级不是列表)
                if not isinstance(current_level, list):
                    current_level = []
                # 扩展列表到所需长度,避免索引越界
                while len(current_level) <= part:
                    current_level.append({})
                current_level = current_level[part]
            else:
                # 处理普通键,最后一层赋值,否则初始化空字典
                if idx == len(key_parts) - 1:
                    current_level[part] = value
                else:
                    if part not in current_level:
                        current_level[part] = {}
                    current_level = current_level[part]
    return result

在视图中使用该函数:

@api_view(['POST'])
@permission_classes([AllowAny])
@parser_classes([FormParser, MultiPartParser])
def test(request):
    parsed_data = parse_form_data(request.data)
    # 现在可以像访问JSON一样操作嵌套数据
    print(parsed_data['company']['company_owner']['email'])
    print(parsed_data['company_details'][0]['documents'])
    # 执行创建企业的逻辑
    return Response()

方案2:使用DRF Serializer自动解析

这是更符合DRF最佳实践的方式,通过定义序列化器自动解析嵌套结构,同时自带数据验证:

首先定义序列化器类:

from rest_framework import serializers

class CompanyOwnerSerializer(serializers.Serializer):
    email = serializers.EmailField()
    phone = serializers.CharField()
    first_name = serializers.CharField()
    last_name = serializers.CharField()

class CompanyDetailSerializer(serializers.Serializer):
    detail = serializers.CharField()

class CompanyDocumentSerializer(serializers.Serializer):
    documents = serializers.ListField(child=serializers.FileField())

class CompanyCreateSerializer(serializers.Serializer):
    company_owner = CompanyOwnerSerializer()
    company_name = serializers.CharField()
    company_email = serializers.EmailField()
    company_mobile_phone = serializers.CharField()
    company_landline = serializers.CharField()
    company_country = serializers.CharField()
    email_otp = serializers.CharField()
    mobile_otp = serializers.CharField()
    company_detail = CompanyDetailSerializer(many=True)
    company_details = CompanyDocumentSerializer(many=True)

然后在视图中使用序列化器处理请求数据:

@api_view(['POST'])
@permission_classes([AllowAny])
@parser_classes([FormParser, MultiPartParser])
def test(request):
    serializer = CompanyCreateSerializer(data=request.data)
    if serializer.is_valid():
        # 验证通过后,validated_data即为嵌套好的结构化数据
        validated_data = serializer.validated_data
        print(validated_data['company_owner']['email'])
        print(validated_data['company_details'][0]['documents'])
        # 在这里执行企业创建逻辑,比如保存到数据库
        return Response({"status": "success"})
    return Response(serializer.errors, status=400)

方案对比

  • 方案1适合快速需求,无需额外定义序列化器,灵活度高;
  • 方案2自带数据校验,代码更规范,适合复杂业务场景和长期维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:42:55