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

Django报错:'OrderedDict'对象无'id'属性,API未接收容器ID

问题原因排查及解决

核心问题:嵌套序列化器过滤了ID字段

你传的容器ID拿不到,本质是嵌套的ContainerSerializer没有将id字段设为可写状态:

  • Django REST Framework的ModelSerializer默认会把主键字段(比如id)标记为read_only=True,在反序列化(接收API请求数据)时,会自动过滤掉前端传入的id值,导致validated_data里的containers列表中每个字典都没有id键。
  • 这就解释了为什么container.get('id')返回None,如果后续代码中误将container当成模型对象而非字典调用属性,就会触发AttributeError。

解决步骤

1. 修改ContainerSerializer,允许ID字段可写

确保ContainerSerializer显式包含id字段,并取消其只读属性:

class ContainerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Container
        # 必须包含id字段,且不要将id放入read_only_fields
        fields = ('id', 'product', 'quantity', 'grade', 'checked_in')
        # 按需指定其他只读字段,不要包含id
        read_only_fields = ()

或者更灵活的方式,单独声明id字段属性:

class ContainerSerializer(serializers.ModelSerializer):
    # 显式声明id字段,允许写入,非必填(新增容器时无需传id)
    id = serializers.CharField(read_only=False, required=False)
    
    class Meta:
        model = Container
        fields = ('id', 'product', 'quantity', 'grade', 'checked_in')

2. 优化GoodsInSerializer的update方法(可选但推荐)

原方法存在冗余逻辑和潜在bug,优化后更简洁可靠:

def update(self, instance, validated_data):
    # 直接使用传入的instance,无需重复查询数据库
    warehouse = validated_data.get('warehouse')
    containers = validated_data.pop('containers', None)

    # 先更新GoodsIn自身的字段
    instance = super().update(instance, validated_data)

    if containers:
        keep_container_ids = []
        # 获取当前关联的所有容器
        existing_containers = Container.objects.filter(goods_in=instance)

        for container_data in containers:
            container_id = container_data.get('id')
            if container_id:
                # 存在ID则更新现有容器
                container_obj = Container.objects.get(id=container_id)
                for key, value in container_data.items():
                    setattr(container_obj, key, value)
                container_obj.save()
            else:
                # 无ID则创建新容器,一次性传入所有参数
                container_obj = Container.objects.create(
                    **container_data,
                    checked_in=False,
                    warehouse_id=warehouse,
                    goods_in=instance
                )
            keep_container_ids.append(container_obj.id)

        # 删除不在保留列表中的容器,用ID对比更可靠
        existing_containers.exclude(id__in=keep_container_ids).delete()

    return instance

额外验证建议

修改后可以在update方法中打印validated_data['containers'],确认前端传入的id已经被包含在验证后的数据中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:35:15