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

DRF多对多关系序列化报错:Producto对象无producto属性

Django REST Framework 订单序列化错误修复

问题现象

插入DetallePedido记录后出现序列化错误:

Got AttributeError when attempting to get a value for field producto on serializer DetallesPedidoSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Producto instance.
Original exception text was: 'Producto' object has no attribute 'producto'.

核心原因

  1. Pedido模型的detalles_pedido是多对多关联到Producto,而非DetallePedido实例;
  2. PedidoSerializer错误地将模型自带的detalles_pedido字段用DetallesPedidoSerializer序列化,导致DRF把Producto实例传入需要DetallePedido实例的序列化器,自然找不到producto属性;
  3. 虽create方法成功插入DetallePedido记录,但序列化时读取的是Pedido关联的Producto集合,而非DetallePedido集合。

修复方案

步骤1:修改序列化器字段映射

在PedidoSerializer中,避免使用模型已有的detalles_pedido字段名,改用DetallePedido的反向关联作为数据源:

# serializers.py
class PedidoSerializer(serializers.ModelSerializer):
    # 用新字段名"detalles",指定数据源为Pedido的DetallePedido反向关联集合
    detalles = DetallesPedidoSerializer(many=True, source='detallepedido_set')
    class Meta:
        model = Pedido
        # 替换原字段为新的"detalles"
        fields = ['cliente', 'direccion', 'estado', 'detalles']
        extra_kwargs = {
            'cliente': {'required': False}
        }

    def create(self, validated_data):
        # 对应修改弹出的字段名为"detalles"
        productos_data = validated_data.pop('detalles')
        pedido = Pedido.objects.create(**validated_data)
        for producto_data in productos_data:
            DetallePedido.objects.create(
                pedido=pedido, 
                producto=producto_data['producto'], 
                cantidad=producto_data['cantidad']
            )
        return pedido

步骤2(可选):优化反向关联命名(更直观)

如果觉得detallepedido_set不够清晰,可在DetallePedido模型中给pedido字段设置related_name:

# models.py
class DetallePedido(models.Model):
    # 添加related_name,让Pedido可以通过pedido.detalles直接访问关联的DetallePedido
    pedido = models.ForeignKey(Pedido, on_delete=models.CASCADE, related_name='detalles')
    producto = models.ForeignKey(Producto, on_delete=models.CASCADE)
    cantidad = models.PositiveIntegerField()

    def __str__(self):
        return f'{self.producto.id} - {self.cantidad} - {self.pedido.cliente}'

此时序列化器中的source可改为更简洁的detalles:

detalles = DetallesPedidoSerializer(many=True, source='detalles')

步骤3:调整请求数据字段名

前端请求时,需把原detalles_pedido字段名改为detalles,示例请求体:

{
  "direccion": "测试地址",
  "estado": "pendiente",
  "detalles": [
    {"producto": 1, "cantidad": 2},
    {"producto": 3, "cantidad": 1}
  ]
}

修复原理

  • 序列化器不再读取Pedido关联的Producto集合,而是直接读取关联的DetallePedido实例集合;
  • DetallesPedidoSerializer接收正确的DetallePedido对象,能正常获取producto和cantidad字段;
  • 保留create方法逻辑,确保DetallePedido记录正确插入数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:52:08