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

DRF中Serializer.data处理多对多关联时抛出AttributeError

问题原因分析

你遇到的AttributeError核心原因是:OrderSerializer的items字段默认关联了Order模型中的items(ManyToMany到MenuItem的集合),但你实际需要序列化的是关联的OrderItem实例。

当DRF执行serializer.data时,会尝试用OrderItemSerializer去序列化MenuItem实例,而OrderItemSerializer中的menu_item_id字段指定了source='menu_item',这会试图在MenuItem实例上查找menu_item属性——显然MenuItem实例没有这个属性,因此抛出错误。

解决方案

有两种简洁的修复方式,选其一即可:

方案一:修改序列化器的source指向

直接在OrderSerializer的items字段中指定source为Order关联的OrderItem集合(默认反向关联名为orderitem_set):

class OrderSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    customer = serializers.CharField(max_length=50)
    order_time = serializers.DateTimeField(read_only=True)
    # 指定source为Order的OrderItem反向关联集合
    items = OrderItemSerializer(many=True, source='orderitem_set')

    def create(self, validated_data):
        # 同步修改create方法中取出的字段名
        order_items_data = validated_data.pop('orderitem_set')
        order = Order.objects.create(**validated_data)
        for order_item_data in order_items_data:
            quantity = order_item_data.pop('quantity')
            menu_item = order_item_data.pop('menu_item')
            OrderItem.objects.create(order=order, quantity=quantity, menu_item=menu_item)
        return order

方案二:修改模型的反向关联名称(更优雅)

修改OrderItem模型的外键字段,添加related_name,让Order实例的items属性直接指向OrderItem集合,同时重命名Order模型的ManyToMany字段避免冲突:

1. 修改模型

class Order(models.Model):
    class OrderStatus(models.TextChoices):
        NEW = "new"
        READY = "ready"
        DELIVERED = "delivered"

    customer = models.CharField(max_length=50)
    order_time = models.DateTimeField(auto_now_add=True)
    # 重命名ManyToMany字段,避免和OrderItem的related_name冲突
    menu_items = models.ManyToManyField(MenuItem, through='OrderItem')
    status = models.CharField(max_length=50, choices=OrderStatus.choices, default=OrderStatus.NEW)

class OrderItem(models.Model):
    # 添加related_name='items',让Order.items直接关联该Order的所有OrderItem
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

2. 保持序列化器不变

此时OrderSerializer的items字段会自动关联Order的OrderItem集合,无需修改:

class OrderSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    customer = serializers.CharField(max_length=50)
    order_time = serializers.DateTimeField(read_only=True)
    items = OrderItemSerializer(many=True)

    def create(self, validated_data):
        order_items_data = validated_data.pop('items')
        order = Order.objects.create(**validated_data)
        for order_item_data in order_items_data:
            quantity = order_item_data.pop('quantity')
            menu_item = order_item_data.pop('menu_item')
            OrderItem.objects.create(order=order, quantity=quantity, menu_item=menu_item)
        return order
修复后效果

执行原请求后,serializer.data会正确返回包含menu_item_id的响应:

{
    "id": 1,
    "customer": "John Doe",
    "order_time": "2024-05-20T12:34:56Z",
    "items": [
        {"id": 1, "menu_item_id": 1, "quantity": 2},
        {"id": 2, "menu_item_id": 2, "quantity": 1}
    ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 15:35:21