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

如何实现通过ID增删订单商品且返回嵌套序列化格式?

解决Django REST Framework中订单商品ID操作与嵌套序列化返回的问题

需求说明

希望通过商品ID完成订单中商品的添加/删除操作,但订单的返回数据需以嵌套序列化器的格式展示商品详情,而非仅返回ID列表。

现有代码

模型定义

class Product(models.Model):
    title = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=1_000, decimal_places=2)

    def __str__(self):
        return self.title

class Order(models.Model):
    date = models.DateField()
    products = models.ManyToManyField(Product, blank=True, related_name='orders')

序列化器定义

class ProductSerializer(serializers.ModelSerializer):
    price = serializers.DecimalField(max_digits=1_000,
                                     decimal_places=2,
                                     coerce_to_string=False)

    class Meta:
        model = Product
        fields = ['id', 'title', 'price']


class OrderSerializer(serializers.ModelSerializer):
    products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), many=True)

    class Meta:
        model = Order
        fields = ['id', 'date', 'products']

期望效果

  • 返回格式:商品以完整嵌套对象展示
{
    "id": 1,
    "date": "2021-08-12",
    "products": [
        {
            "id": 1,
            "title": "Item 1",
            "price": 19.99
        },
        {
            "id": 3,
            "title": "Item 3",
            "price": 49.99
        }
    ]
}
  • 输入格式:创建/更新时仅需传入商品ID列表
// 创建订单
{
    "date": "2021-08-12",
    "products":[1, 3]
}

// 添加商品(ID=2)
{
    "id": 1,
    "date": "2021-08-12",
    "products":[1, 3, 2]
}

正确实现方法

方法一:重写to_representation方法

这是最直接的方案,保持原有字段名,仅在序列化输出时替换为嵌套数据:

class OrderSerializer(serializers.ModelSerializer):
    products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), many=True)

    class Meta:
        model = Order
        fields = ['id', 'date', 'products']

    def to_representation(self, instance):
        # 获取父类生成的基础序列化数据(此时products是ID列表)
        data = super().to_representation(instance)
        # 用ProductSerializer序列化订单关联的所有商品,替换原products字段
        data['products'] = ProductSerializer(instance.products.all(), many=True).data
        return data

关键修正点:

  • 原代码错误地将instance当作字典访问(instance['products']),实际instance是Order模型实例,需通过instance.products.all()获取关联商品查询集
  • 序列化多个商品时必须添加many=True参数
  • 需调用序列化器的.data属性获取最终序列化结果

方法二:区分读写字段(更清晰)

通过定义两个字段分别处理输入(ID列表)和输出(嵌套对象),逻辑更明确:

class OrderSerializer(serializers.ModelSerializer):
    # 仅用于接收输入:商品ID列表,写入后不返回
    products = serializers.PrimaryKeyRelatedField(
        queryset=Product.objects.all(),
        many=True,
        write_only=True
    )
    # 仅用于输出:嵌套商品详情,只读不接收输入
    products_details = ProductSerializer(many=True, read_only=True, source='products')

    class Meta:
        model = Order
        fields = ['id', 'date', 'products', 'products_details']

使用说明:

  • 创建/更新时传入products字段(ID列表)
  • 返回结果中products_details字段会展示完整的商品嵌套数据

如果希望保持返回字段名为products,可以调整为:

class OrderSerializer(serializers.ModelSerializer):
    # 内部字段:仅处理输入
    _products = serializers.PrimaryKeyRelatedField(
        queryset=Product.objects.all(),
        many=True,
        write_only=True,
        source='products'
    )
    # 对外字段:仅处理输出
    products = ProductSerializer(many=True, read_only=True)

    class Meta:
        model = Order
        fields = ['id', 'date', 'products', '_products']

验证效果

两种方法都能满足需求:

  1. 创建/更新订单时,仅需传入商品ID列表
  2. 返回的订单数据中,商品以完整嵌套对象的形式展示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:39:52