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

Django Rest Framework POST请求出现KeyError: 'folder'问题求助

解决DRF POST时的KeyError: 'folder'问题

嘿,我来帮你搞定这个问题!你遇到的KeyError: 'folder'主要是两个细节没处理对,咱们一步步来修复:

问题根源分析

  1. Serializer字段配置错误:你在TodoSerializer里给folder字段设置了read_only=True,这会告诉DRF:这个字段只负责把模型数据转成JSON(序列化),完全不处理从JSON转模型的过程(反序列化)。所以POST请求里的folder数据根本不会被解析到validated_data里,自然pop('folder')的时候就找不到这个键了。
  2. Create方法逻辑错误:你的Todo模型里folder是ForeignKey(一对多关系,一个Folder对应多个Todo),但你在create方法里写了循环创建Folder的逻辑,这完全不符合外键的关联逻辑,反而会引发额外错误。

修复方案

方案A:通过Folder的ID关联已有文件夹(最常用场景)

这种方式适合你已经提前创建好Folder,只需要在创建Todo时关联它的ID:

修改serializers.py的TodoSerializer:

class TodoSerializer(serializers.ModelSerializer):
    # 保留序列化时返回完整Folder数据的能力
    folder_detail = FolderSerializer(source='folder', read_only=True)
    # 用PrimaryKeyRelatedField处理外键的写入逻辑
    folder = serializers.PrimaryKeyRelatedField(queryset=models.Folder.objects.all())

    class Meta:
        fields = ('id','title','description','folder', 'folder_detail',)
        model = models.Todo
        extra_kwargs = {
            "id":{
                "required":False,
                "read_only":False
            }
        }

    # 不需要自定义create方法,DRF会自动处理外键关联

对应的POST请求可以改成:

{
  "id": 4,
  "title": "Python",
  "description": "Learn python lesson",
  "folder": 1
}

方案B:支持传入完整Folder数据并自动创建(如果不存在)

如果你想保持原始的POST数据格式(传入完整的Folder对象),可以这样修改:

修改serializers.py的TodoSerializer:

class TodoSerializer(serializers.ModelSerializer):
    folder = FolderSerializer()  # 去掉read_only和required=False,允许写入

    class Meta:
        fields = ('id','title','description','folder',)
        model = models.Todo
        extra_kwargs = {
            "id":{
                "required":False,
                "read_only":False
            }
        }

    def create(self, validated_data):
        # 取出folder的字典数据
        folder_data = validated_data.pop('folder')
        # 用get_or_create确保:如果Folder的ID存在就直接关联,不存在就创建新的
        folder, created = models.Folder.objects.get_or_create(
            id=folder_data.get('id'),
            defaults={'name': folder_data['name']}
        )
        # 创建Todo并关联目标Folder
        todo = models.Todo.objects.create(folder=folder, **validated_data)
        return todo

这样你的原始POST数据就能正常使用了:

{
  "id": 4,
  "title": "Python",
  "description": "Learn python lesson",
  "folder": {
    "id": 1,
    "name": "Lesson"
  }
}

补充说明

原来的create方法里写了for data in folder_data:,但folder_data是单个字典(你传入的是单个Folder对象),不是列表,循环会直接报错。而且因为是ForeignKey,一个Todo只能关联一个Folder,完全不需要循环处理~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:33:42