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

Django REST Framework处理multipart/form-data时报category字段必填错误

问题根因

你遇到的报错是三个原因共同导致的:

  • DRF 自带的 MultiPartParser、FormParser 不支持解析 category[0]、variants[0][price] 这种带方括号的嵌套表单格式,这类字段会被识别为独立的零散字段,不会被整合成 category、variants 数组传递给序列化器
  • 你的序列化器中 category 字段对应模型的多对多关系,没有显式指定 many=True,即使拿到数组也会校验不通过
  • 额外注意:请求体里的字段名是 service,但模型和序列化器里定义的是 services,字段名不匹配也会导致校验失败

修复方案

第一步:修正序列化器配置

给 category 字段显式指定多对多属性:

class AddProductSerializer(serializers.ModelSerializer):
    id = serializers.PrimaryKeyRelatedField(read_only=True)
    variants = VariantSerializer(many=True)
    slug = serializers.SlugField(read_only=True)
    # 新增:指定category为多值主键字段
    category = serializers.PrimaryKeyRelatedField(many=True, queryset=Category.objects.all())
    
    class Meta:
        model = Product
        fields = ['id','merchant','featured', 'top_rated','category','brand','collection','sub_category',
                  'name','slug','description', 'main_product_image','best_seller','picture',
                  'rating','availability','warranty','services','variants']
    # 其余create逻辑保持不变

第二步:处理嵌套表单解析问题

两种方案可选:

方案1:前端改造(成本更低)

前端构造FormData时,将category、variants这类数组字段转为JSON字符串传递,后端序列化器新增自定义反序列化逻辑:

# 序列化器新增字段处理逻辑
import json
class AddProductSerializer(serializers.ModelSerializer):
    # ... 其余字段不变
    def to_internal_value(self, data):
        # 解析JSON格式的数组字段
        if isinstance(data.get('category'), str):
            data['category'] = json.loads(data['category'])
        if isinstance(data.get('variants'), str):
            data['variants'] = json.loads(data['variants'])
        return super().to_internal_value(data)

方案2:后端自定义解析器(适配原有前端传参格式)

自定义支持嵌套表单的解析器,替换原有视图的parser_classes:

from rest_framework.parsers import MultiPartParser
import re
from django.utils.datastructures import MultiValueDict

class NestedMultiPartParser(MultiPartParser):
    def parse(self, stream, media_type=None, parser_context=None):
        parsed = super().parse(stream, media_type, parser_context)
        data = {}
        for key, value in parsed.data.items():
            # 解析带方括号的嵌套键
            keys = re.findall(r'([^\[\]]+)', key)
            current = data
            for i, k in enumerate(keys[:-1]):
                if k not in current:
                    if keys[i+1].isdigit():
                        current[k] = []
                    else:
                        current[k] = {}
                current = current[k]
            last_k = keys[-1]
            if isinstance(current, list):
                idx = int(last_k)
                while len(current) <= idx:
                    current.append({})
                current[idx] = value
            else:
                current[last_k] = value
        parsed.data = MultiValueDict(data)
        return parsed

然后修改视图的parser配置:

class ProductAddAPIView(CreateAPIView):
    permission_classes = [IsAuthenticated]
    # 替换为自定义的嵌套解析器
    parser_classes = [NestedMultiPartParser, JSONParser]
    serializer_class = AddProductSerializer

第三步:修正请求字段名

将请求体中的service字段改为services,和模型定义保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 03:45:08