DRF可浏览API访问列表视图触发create权限引发KeyError如何解决
解决方案
方案1:修复权限类逻辑(最推荐,无副作用)
你的IsListItemOwner权限类本身存在健壮性问题:没有处理list_id不存在、对应List对象不存在的场景,就算没有可浏览API的问题,恶意请求也会触发500错误。修改后的权限类代码如下:
from rest_framework import permissions from rest_framework.exceptions import NotFound class IsListItemOwner(permissions.BasePermission): def has_permission(self, request, view): if view.action == "create": # 从request.data安全读取list_id,不存在则返回None list_id = request.data.get("list_id") # 可浏览API渲染表单时无提交数据,直接返回True允许显示表单 # 真实POST请求如果未传list_id,会被序列化器的required校验拦截,返回400错误 if not list_id: return True # 捕获List不存在的异常,返回规范的404错误 try: list_obj = List.objects.get(pk=list_id) except List.DoesNotExist: raise NotFound("指定的列表不存在") return list_obj.user == request.user return True def has_object_permission(self, request, view, obj): return obj.get_root().list.user == request.user
修改后即可正常使用可浏览API,同时补全了权限类的异常处理逻辑,避免恶意请求触发500错误。
方案2:自定义表单渲染逻辑(可选,适合不需要在列表页显示创建表单的场景)
如果你不需要在列表页展示创建表单,可以重写可浏览API渲染器的表单显示判断,直接隐藏列表页的创建表单:
class ListItemViewSet(viewsets.ModelViewSet): queryset = ListItem.objects.all() # 其余原有逻辑保持不变 def get_renderers(self): renderers = super().get_renderers() if self.action == "list": from rest_framework.renderers import BrowsableAPIRenderer # 自定义渲染器,隐藏列表页的POST创建表单 class NoFormBrowsableAPIRenderer(BrowsableAPIRenderer): def show_form_for_method(self, view, method, request, obj): if method == "POST": return False return super().show_form_for_method(view, method, request, obj) # 替换原有可浏览API渲染器 for i, renderer in enumerate(renderers): if isinstance(renderer, BrowsableAPIRenderer): renderers[i] = NoFormBrowsableAPIRenderer() return renderers
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

