Django Rest Framework POST请求出现KeyError: 'folder'问题求助
解决DRF POST时的KeyError: 'folder'问题
嘿,我来帮你搞定这个问题!你遇到的KeyError: 'folder'主要是两个细节没处理对,咱们一步步来修复:
问题根源分析
- Serializer字段配置错误:你在
TodoSerializer里给folder字段设置了read_only=True,这会告诉DRF:这个字段只负责把模型数据转成JSON(序列化),完全不处理从JSON转模型的过程(反序列化)。所以POST请求里的folder数据根本不会被解析到validated_data里,自然pop('folder')的时候就找不到这个键了。 - 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
相关产品推荐
相关产品推荐

