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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:06:30