Django DRF使用@action(detail=True)触发pk组重定义错误的原因?
问题原因解析
核心触发点:URL路由重复匹配导致pk命名组冲突
你的urls.py存在重复包含路由的错误,结合detail=True的@action装饰器的路由生成规则,就触发了命名组重复定义的问题:
DefaultRouter注册doctor视图集后,会自动生成两类基础路由:- 列表路径:
/viewset/doctor/ - 详情路径:
/viewset/doctor/<int:pk>/
- 列表路径:
- 当你给
verify方法加detail=True的@action装饰器时,DRF会额外生成一个带pk参数的详情动作路由:/viewset/doctor/<int:pk>/verify/ - 但你在
urlpatterns里重复写了两次include(router.urls),第二次的前缀是path('viewset/<int:pk>', include(router.urls)),这就导致所有router生成的路由,都会多套一层你手动加的<int:pk>参数:- 原本的详情路由会变成:
/viewset/<int:pk>/doctor/<int:pk>/ - 额外的verify动作路由会变成:
/viewset/<int:pk>/doctor/<int:pk>/verify/
Django的URL解析器不允许同一条路由里出现同名的命名组,两个路由参数都叫pk,所以直接抛出重定义错误。
- 原本的详情路由会变成:
为什么去掉detail=True就正常了?
当你把detail=True移除后,verify变成列表级动作,生成的路由是/viewset/doctor/verify/,不会带第二层<int:pk>参数,也就不会出现两个pk命名组冲突的情况,但这时候你的verify方法本来是要操作单个doctor实例的,改成detail=False之后功能不符合预期。
修复方案
直接删除urls.py里重复的那行路由即可,修改后urlpatterns如下:
router = DefaultRouter() router.register('doctor', views.DoctorViewSet, basename='doctor') urlpatterns = [ path('viewset/', include(router.urls)), # 删掉下面这行重复包含路由的代码 # path('viewset/<int:pk>', include(router.urls)), ]
修改后两类路径都可以正常访问:
- 单实例详情路径:
/app_api/viewset/doctor/6/ - 验证动作路径:
/app_api/viewset/doctor/6/verify/(支持PATCH方法更新is_verified字段)
内容的提问来源于stack exchange,提问作者pikunimohanty
相关产品推荐
相关产品推荐

