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
相关产品推荐
相关产品推荐

