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

Django Rest Framework嵌套序列化器创建更新产品时415错误如何解决

问题根因

你碰到的415错误完全是请求格式不对导致的:

  • JSON(application/json)本身不支持传输二进制文件,你在JSON里塞File字段本身就不符合规范,DRF自然不认这种请求
  • 带文件上传的请求必须用multipart/form-data格式提交,还要确保你的视图类配置了对应的解析器:
from rest_framework.parsers import MultiPartParser, FormParser

class ProductViewSet(viewsets.ModelViewSet):
    parser_classes = (MultiPartParser, FormParser)
    # 其余配置不变

下一步修改步骤

1. 调整请求参数格式

multipart/form-data不支持直接传嵌套数组,有两种兼容方案:
方案一(推荐,前后端对接更简单):把数组字段按索引展开提交:

# 普通字段直接传
name: first product
category: tops
brand: first
...其余普通字段
image_1: [文件对象]
image_2: [文件对象]
# 变体按索引传
variants[0].price: 23000
variants[0].quantity:4
variants[0].image: [第一个变体的文件对象]
variants[0].size: m
...第一个变体其余字段
variants[1].price:44
variants[1].quantity:44
...以此类推

方案二:把variants的非文件字段序列化成JSON字符串传,文件单独传,后端自己解析重组,相对麻烦一点。

2. 修复序列化器的现有bug

你现在的序列化器有几个明显的错误会导致后续运行失败:

  • 所有validate_方法都没有返回校验后的值,DRF校验完会把返回值放到validated_data里,你没return的话对应字段会丢失:
def validate_category(self, value):
    if not Category.objects.filter(slug=value).exists():
        raise serializers.ValidationError({'category': 'category does not exist!'})
    return value # 必须加

def validate_store(self, value):
    request = self.context.get('request')
    if not Store.objects.filter(id=value, user=request.user).exists():
        raise serializers.ValidationError({'store': 'Store does not exist!'})
    return value # 必须加
  • category是ForeignKey不是多对多字段,不能用product.category.set(category),直接赋值就行:
# 把这两行
category = get_object_or_404(Category, slug=category)
product.category.set(category)
# 改成
product.category = get_object_or_404(Category, slug=category)
  • 上传image_2的时候你误用了image_1的文件,导致两张图一模一样:
# 把这行
image_2_data = cloudinary.uploader.upload(image_1, ...)
# 改成
image_2_data = cloudinary.uploader.upload(image_2, ...)
  • 创建变体的时候没必要重复调用VariantSerializer校验,已经在父序列化器校验过了,直接创建对象就行:
for variant in variants:
    image = variant.pop("image")
    new_variant = Variant.objects.create(product=product, **variant)
    # 后面的上传逻辑不变

3. 新增更新逻辑

要实现更新时同时修改关联变体,重写序列化器的update方法即可:

def update(self, instance, validated_data):
    variants = validated_data.pop('variants', None)
    # 先更新Product本身的字段
    for attr, value in validated_data.items():
        # 如果是图片文件就走上传逻辑,这里可以抽成公共方法复用create里的上传代码
        if attr in ['image_1', 'image_2']:
            # 调用你写的cloudinary上传逻辑,返回url赋值给instance对应字段
            pass
        else:
            setattr(instance, attr, value)
    instance.save()
    
    if variants is not None:
        # 软删除不在请求里的旧变体
        existing_variant_ids = [v['id'] for v in variants if 'id' in v]
        instance.variants.exclude(id__in=existing_variant_ids).update(is_deleted=True)
        
        for variant_data in variants:
            # 传了id的更新现有变体,没传的新建
            if 'id' in variant_data:
                variant = instance.variants.get(id=variant_data['id'])
                for attr, value in variant_data.items():
                    if attr == 'image' and isinstance(value, UploadedFile):
                        # 走图片上传逻辑
                        pass
                    else:
                        setattr(variant, attr, value)
                variant.save()
            else:
                # 走新建变体的逻辑,和create方法里的逻辑一致
                pass
    return instance

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 19:57:01