Django REST kwargs传参异常 修改pk后接口返回404问题
问题背景
- 基于Django REST框架搭建了配置
default_lookup = pk的用户详情接口 - 预期逻辑:传入的
pk参数等于9999999999时,自动返回当前已登录用户的详情数据 - 异常现象:日志显示
kwargs中的pk值已被修改为当前登录用户ID13,但接口依然返回404 Not Found错误
原问题代码
class UserDetailView(generics.RetrieveUpdateDestroyAPIView): serializer_class = UserSerializer queryset = User.objects.all() def get(self,*args,**kwargs): pk = kwargs.get('pk') print(kwargs) print(f"pk {pk}") if pk == 9999999999: kwargs['pk'] = self.request.user.id print(kwargs) return self.retrieve(self,*args,**kwargs)
控制台运行日志
{'pk': 9999999999} pk 9999999999 {'pk': 13} Not Found: /api/users/9999999999
问题根因
404错误来自三处代码逻辑问题,和DRF视图的内置执行逻辑不匹配:
- 参数作用域错误:
get方法中修改的kwargs是当前函数的局部变量,而DRF内置查询逻辑读取的是视图实例挂载的self.kwargs(路由解析完成后绑定到视图的原始参数,pk值始终为9999999999),局部变量的修改不会影响实例属性,因此底层查询时依然用9999999999查库,自然返回404。 - 方法传参错误:
retrieve是类实例方法,通过self.retrieve()调用时Python会自动注入当前视图实例作为方法的第一个self参数,手动额外传入self作为位置参数会导致方法内部参数顺序全乱,request等核心参数错位,逻辑执行异常。 - 逻辑覆盖不全:仅重写
get方法只能让特殊pk规则对GET请求生效,后续PUT/PATCH/DELETE请求走内置逻辑时不会触发pk替换,规则无法覆盖全量请求方法。
修复方案
DRF的RetrieveUpdateDestroyAPIView预留了get_object扩展点用于自定义目标对象查找逻辑,全量请求方法都会复用该逻辑,不需要单独重写每个请求方法,也不需要手动处理参数传递。
修复后代码如下:
from rest_framework import generics from rest_framework.exceptions import NotAuthenticated class UserDetailView(generics.RetrieveUpdateDestroyAPIView): serializer_class = UserSerializer queryset = User.objects.all() # 提取魔法值为常量,便于后续维护 CURRENT_USER_SPECIAL_PK = 9999999999 def get_object(self): # 统一转换pk类型,兼容字符串/整数格式的路径参数 raw_pk = self.kwargs.get(self.lookup_field) try: pk = int(raw_pk) except (TypeError, ValueError): pk = None # 匹配特殊pk时直接返回当前登录用户 if pk == self.CURRENT_USER_SPECIAL_PK: if not self.request.user.is_authenticated: raise NotAuthenticated() return self.request.user # 普通pk走默认查询逻辑 return super().get_object()
内容的提问来源于stack exchange,提问作者Aycone
相关产品推荐
相关产品推荐

