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

Django REST Framework嵌套序列化器POST请求问题排查

问题描述

我有一个与Brand模型存在多对一关系的Product模型:

class Product(models.Model):
    name = models.CharField(max_length=200)
    description = models.CharField(max_length=500)
    sku = models.CharField(max_length=50)
    upc = models.CharField(max_length=12, blank=True)
    asin = models.CharField(max_length=10, blank=True)
    brand = models.ForeignKey(
        Brand,
        on_delete=models.CASCADE,
        null=True,
    )
    # buybox = models.FloatField(blank=True)
    vendors = models.ManyToManyField(Vendor, blank=True)
    added = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name + ": " + self.description

Brand模型:

class Brand(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

同时使用了嵌套序列化器:

class ProductSerializer(serializers.ModelSerializer):
    brand = BrandSerializer(required=False, read_only=True)

    class Meta:
        model = Product
        fields = "__all__"

当我发送POST请求添加新产品时持续报错,无法确定正确的JSON请求结构。目前只有发送以下JSON不会触发Axios错误,但添加到数据库的产品brand字段为NULL:

{
  "name": "examplename",
  "description": "example desc",
  "sku": "SKUSKUSKU",
  "asin": "ASINASIN12",
  "price": "11.11",
  "brand": {
    "id": 1,
    "name": "Honeywell"
  }
}

请求发送函数如下:

function addProduct(product) {
    // axios post request for a new product
    console.log(product)
    axios.post("http://127.0.0.1:8000/products/", product)
        .then((response) => {
            console.log(response);
            alert("Success");
            reset('productForm')

        })
        .catch((error) => {
            console.log(error);
            alert(error);
        })
}

补充说明:从Django后台手动创建的单个产品的GET请求返回的正确JSON:

{
        "id": 9,
        "brand": {
            "id": 2,
            "name": "Beano"
        },
        "vendors": [],
        "name": "beans",
        "description": "big ol can o beans",
        "sku": "beansbeansbeans",
        "upc": "",
        "asin": "bB00nvn",
        "added": "2022-12-28T19:09:30.007480Z",
        "updated": "2022-12-28T19:09:30.013781Z"
    }

请问在向存在关联关系的模型发送POST请求时,是应该发送brand的主键ID,还是发送完整的嵌套brand对象?我哪里操作出错了?


解决方案

问题根源

你的ProductSerializer里给brand字段设置了read_only=True,这意味着序列化器只会在**读取(GET)时返回嵌套的Brand数据,但写入(POST/PUT)**时会完全忽略这个字段的输入,所以你传的brand对象根本没被处理,导致数据库里brand字段为NULL。

正确处理方式

分两种场景选择:

  1. 仅关联已存在的Brand

    • 不需要嵌套序列化器,直接用DRF默认的外键处理逻辑,发送Brand的ID即可。修改序列化器:
      class ProductSerializer(serializers.ModelSerializer):
          class Meta:
              model = Product
              fields = "__all__"
      
    • 对应的POST请求JSON只需传brand的ID:
      {
        "name": "examplename",
        "description": "example desc",
        "sku": "SKUSKUSKU",
        "asin": "ASINASIN12",
        "price": "11.11",
        "brand": 1
      }
      
  2. 需要同时创建新Brand并关联到Product

    • 如果需求是允许添加Product时同步创建新Brand,需要给BrandSerializer移除read_only=True,并在ProductSerializer里重写create方法处理嵌套对象:
      class BrandSerializer(serializers.ModelSerializer):
          class Meta:
              model = Brand
              fields = "__all__"
      
      class ProductSerializer(serializers.ModelSerializer):
          brand = BrandSerializer(required=False)
      
          class Meta:
              model = Product
              fields = "__all__"
      
          def create(self, validated_data):
              # 取出嵌套的brand数据
              brand_data = validated_data.pop('brand', None)
              product = Product.objects.create(**validated_data)
              if brand_data:
                  # 用get_or_create避免重复创建同名Brand
                  brand, created = Brand.objects.get_or_create(**brand_data)
                  product.brand = brand
                  product.save()
              return product
      
    • 此时可以发送完整的Brand对象来创建关联,也可以传已存在Brand的ID+名称(通过get_or_create自动匹配已有数据)。

总结

  • 仅关联已有Brand时,直接传ID最简洁,序列化器无需嵌套。
  • 需要同步创建新Brand时,才用嵌套序列化器并重写create方法。
  • 你之前的核心错误就是把brand字段设为read_only,导致写入时该字段被完全忽略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:50:29