使用DRF APIView与drf_yasg时出现未定义的额外POST接口
解决Swagger中出现未定义的/users/{id}/POST接口问题
问题根源
- 你将带
pk的/users/{id}/和不带pk的/users/都映射到同一个UserApiView,drf_yasg会默认把视图中定义的所有HTTP方法(比如你的post方法)关联到所有映射的URL上,导致不该存在的/users/{id}/POST接口被生成。 - 视图中定义了两个同名的
get方法,Python中后定义的方法会覆盖前一个,这会导致/users/的GET请求也执行带pk的逻辑,属于隐藏bug。
方案1:拆分视图(推荐)
把列表操作和详情操作拆分成两个独立的APIView,让每个视图只处理对应URL的方法,Swagger就能正确生成文档:
URL配置修改
urlpatterns = [ path('users/', UserListApiView.as_view()), path('users/<str:pk>/', UserDetailApiView.as_view()), ]
视图拆分实现
class UserListApiView(APIView): @swagger_auto_schema( request_body=CreateUserSerializer, responses={'200': openapi.Response('response description', DetailUserSerializer)} ) def post(self, request): # 修正:原代码缺少data参数,序列化器无法正确处理请求数据 user_data = CreateUserSerializer(data=request.data) user_data.is_valid(raise_exception=True) new_user = user_data.save() return Response(DetailUserSerializer(new_user).data) @swagger_auto_schema( responses={'200': openapi.Response('response description', DetailUserSerializer(many=True))} ) def get(self, request): queryset = UserRepo().get_all() serializer = DetailUserSerializer(queryset, many=True) return Response({'data': serializer.data}) class UserDetailApiView(APIView): @swagger_auto_schema( responses={'200': openapi.Response('response description', DetailUserSerializer)} ) def get(self, request, pk=None): queryset = UserRepo().get_all() user = get_object_or_404(queryset, pk=pk) serializer = DetailUserSerializer(user) return Response(serializer.data)
方案2:限制带pk URL的允许方法
如果不想拆分视图,可以在映射带pk的URL时,通过as_view()的methods参数限制仅允许GET方法,同时修正视图中get方法覆盖的问题:
URL配置修改
urlpatterns = [ path('users/', UserApiView.as_view()), # 仅允许GET方法访问带pk的接口 path('users/<str:pk>/', UserApiView.as_view(methods=['GET'])), ]
视图修正
class UserApiView(APIView): @swagger_auto_schema( request_body=CreateUserSerializer, responses={'200': openapi.Response('response description', DetailUserSerializer)} ) def post(self, request): # 修正:原代码缺少data参数 user_data = CreateUserSerializer(data=request.data) user_data.is_valid(raise_exception=True) new_user = user_data.save() return Response(DetailUserSerializer(new_user).data) @swagger_auto_schema( responses={ '200': openapi.Response( 'response description', DetailUserSerializer(many=True) if not pk else DetailUserSerializer ) } ) def get(self, request, pk=None): if pk is None: queryset = UserRepo().get_all() serializer = DetailUserSerializer(queryset, many=True) return Response({'data': serializer.data}) else: queryset = UserRepo().get_all() user = get_object_or_404(queryset, pk=pk) serializer = DetailUserSerializer(user) return Response(serializer.data)
内容的提问来源于stack exchange,提问作者Alexandr Sokolov
相关产品推荐
相关产品推荐

