Django Rest Framework处理嵌套字典报KeyError:'client'问题求解
问题根因
出现KeyError: 'client'是三个明显的实现错误导致的:
- 字段名完全搞反了:Order模型中关联Client的外键字段名是
client,你序列化器里定义的字段叫orders——orders是ForeignKey参数里设置的related_name,作用是让Client实例可以反向查询关联的订单,根本不是Order模型自身的字段。同时你在fields列表里也没有声明client字段,反序列化时收到传入的client键找不到匹配的序列化字段,直接触发键错误。 - 字段类型和入参结构不匹配:
SlugRelatedField只支持接收单值作为关联查询依据(比如直接传client的手机号字符串),你当前传入的client是包含name、surname、phone等多个属性的嵌套字典,SlugRelatedField根本无法解析这种结构。 - 字段权限设置错误:你给字段加了
read_only=True标记,这个参数控制的字段只会在序列化输出时返回数据,不会接收POST提交的入参,反序列化阶段会直接忽略该字段的值,就算字段名写对也无法实现关联逻辑。
解决方案
根据实际业务需求二选一即可:
方案1:嵌套创建Client(适配你当前传嵌套字典的入参结构)
如果需要在提交订单时同步创建关联的Client信息,使用嵌套序列化器实现即可,注意DRF默认嵌套序列化器不支持写操作,需要手动重写create方法处理嵌套写入:
首先定义Client的基础序列化器:
class ClientSerializer(serializers.ModelSerializer): class Meta: model = Client fields = ['name', 'surname', 'phone', 'adress']
然后修改Order序列化器:
class OrderSerializer(serializers.ModelSerializer): # 字段名必须和模型外键名一致,为client而非orders client = ClientSerializer() class Meta: model = Order # 必须把client加入字段列表,模型未定义的products、delivery_date不要传入,或先给模型补充对应字段 fields = ['title', 'description', 'delivery_code', 'delivery_adress', 'client'] def create(self, validated_data): # 提取嵌套的客户端数据 client_data = validated_data.pop('client') # 先创建Client实例 client = Client.objects.create(**client_data) # 再创建订单并关联已创建的客户端 order = Order.objects.create(client=client, **validated_data) return order
方案2:用SlugRelatedField按手机号关联已有Client
如果不需要新建Client,仅需要把订单关联到已存在、手机号匹配的Client上,首先要修改入参格式,不要传嵌套的client字典,直接传Client的手机号作为单值:
// 调整后的入参结构 { "title": "Test title10", "description": "Test description10", "client": "1645342534532", // 直接传手机号字符串,不要传嵌套对象 "delivery_adress": "st. Egor44", "delivery_code": "4562gdgll" }
对应的序列化器代码:
class OrderSerializer(serializers.ModelSerializer): # 字段名为client,去掉read_only参数,指定queryset允许反序列化时查询匹配 client = serializers.SlugRelatedField( slug_field='phone', queryset=Client.objects.all() ) class Meta: model = Order fields = ['title', 'description', 'delivery_code', 'delivery_adress', 'client']
注意:使用该方案需要给Client模型的phone字段加
unique=True约束,否则存在多个同手机号Client时会触发MultipleObjectsReturned错误。
额外提两个代码里的小问题:
- 你当前入参传了
products、delivery_date字段,但Order模型里没有定义这两个字段,要么给模型补充对应字段,要么从入参里去掉,否则校验时会报无效字段错误。 - 你传入的
delivery_date值2022-23-09:44:00格式非法,标准datetime格式为YYYY-MM-DD HH:MM:SS,且月份取值范围为1-12,不存在23月的合法值。
内容的提问来源于stack exchange,提问作者Vladimir Irkhin
相关产品推荐
相关产品推荐

