DRF ViewSet执行动作多次且GET请求action为None求助
DRF ViewSet动作重复执行及action为None异常分析与解决
问题概述
使用Django REST Framework的ViewSet实现list、create等动作,发送GET请求时出现部分动作重复执行,且self.action有时为None。移除DjangoModelPermissions后,action为None的现象消失,但仍未明确问题根源及解决办法。
原因分析
1. action为None的根源
DjangoModelPermissions的权限检查逻辑会主动调用view.get_queryset(),而此时DRF还未完成路由到动作的映射(即self.action尚未被赋值),因此在get_queryset中会捕获到action为None的情况。
2. 动作重复执行的原因
get_queryset被多次调用:权限检查阶段(如DjangoModelPermissions触发)会调用一次,视图处理逻辑执行时又会调用一次,导致控制台重复输出动作名称。- 原代码逻辑过度依赖
action判断查询集,当action为None时会进入错误分支,可能触发额外的查询或逻辑执行,加剧重复现象。
解决方案
1. 重构get_queryset,摆脱对action的依赖
优先通过路由参数(而非action)判断返回的查询集,避免action未赋值时的逻辑错误:
def get_queryset(self): print(self.action) pk = self.kwargs.get("pk") questionnaire_id = self.kwargs.get("questionnaire_id") if pk: return Question.objects.filter(pk=pk) elif questionnaire_id: return Question.objects.filter(questionnaire=questionnaire_id) # 兜底逻辑,根据业务需求调整 return Question.objects.none()
2. 优化权限配置,避免不必要的DjangoModelPermissions调用
调整get_permissions逻辑,确保DjangoModelPermissions仅在需要的动作中使用:
def get_permissions(self): # 仅对需要模型权限的动作使用DjangoModelPermissions if self.action in ["create", "update", "partial_update", "destroy"]: permission_classes = [DjangoModelPermissions] else: permission_classes = [IsStaffDoctorOrIsStaffHumanResource] return [permission() for permission in permission_classes]
注意:使用
DjangoModelPermissions时,需确保用户拥有对应模型的权限(如add_question、change_question等),否则会导致权限校验失败。
3. 排查请求重复问题
检查前端是否存在重复发送请求的情况,或服务器是否有重定向、中间件触发额外请求的逻辑,这也可能导致动作重复执行。
验证效果
修改后重新测试,self.action为None的现象会消失,get_queryset的调用次数会恢复正常(单次请求对应必要的调用次数)。
内容的提问来源于stack exchange,提问作者Hamidreza Farzin
相关产品推荐
相关产品推荐

