使用DRF时单类继承多APIView导致Swagger出现重复URL条目
解决DRF视图集成后Swagger接口重复问题
问题原因
当视图类同时继承ListAPIView和UpdateAPIView时,DRF-YASG(Swagger生成工具)会扫描所有父类支持的HTTP方法(ListAPIView支持GET,UpdateAPIView支持PUT/PATCH),再加上URL配置中未明确限定方法,就会导致每个URL下出现重复的接口条目。
解决方案
方案1:改用ViewSet(推荐)
ViewSet能清晰管理方法与URL的映射,DRF-YASG可自动识别正确接口,避免重复:
# views.py from rest_framework import viewsets from .models import YourModel from .serializers import YourSerializer class EscalatedStatusViewSet(viewsets.GenericViewSet, viewsets.mixins.ListModelMixin, viewsets.mixins.CreateModelMixin, viewsets.mixins.UpdateModelMixin): queryset = YourModel.objects.all() serializer_class = YourSerializer
# urls.py from rest_framework.routers import DefaultRouter from .views import EscalatedStatusViewSet router = DefaultRouter() router.register(r'escalated-status', EscalatedStatusViewSet, basename='escalated-status') urlpatterns = [ # 其他URL配置 *router.urls, ]
此配置会让Swagger生成3条正确接口:
GET /escalated-status/(列表查询)POST /escalated-status/(提交数据)PUT /escalated-status/<pk>/(更新数据)
方案2:明确URL的actions并控制Swagger展示
如果不想改用ViewSet,可通过as_view(actions)限定每个URL的方法,并用DRF-YASG装饰器排除冗余方法:
# views.py from rest_framework.generics import ListAPIView, UpdateAPIView from rest_framework import status from rest_framework.response import Response from drf_yasg.utils import swagger_auto_schema from .models import YourModel from .serializers import YourSerializer class EscalatedStatusListView(ListAPIView, UpdateAPIView): queryset = YourModel.objects.all() serializer_class = YourSerializer # 实现POST方法(ListAPIView默认无此方法) def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) # 让Swagger在列表URL中忽略PUT/PATCH @swagger_auto_schema(auto_schema=None) def put(self, request, *args, **kwargs): return super().put(request, *args, **kwargs) @swagger_auto_schema(auto_schema=None) def patch(self, request, *args, **kwargs): return super().patch(request, *args, **kwargs)
# urls.py from django.urls import path from .views import EscalatedStatusListView urlpatterns = [ path('escalated-status/', EscalatedStatusListView.as_view(actions={'get': 'list', 'post': 'post'}), name='escalated-status-list'), path('escalated-status/<int:pk>/', EscalatedStatusListView.as_view(actions={'put': 'update'}), name='escalated-status-update'), ]
方案3:直接继承GenericAPIView并混入Mixin
避免继承完整的ListAPIView和UpdateAPIView,仅继承GenericAPIView并混入所需Mixin,精准控制支持的方法:
# views.py from rest_framework import generics, mixins from rest_framework import status from rest_framework.response import Response from .models import YourModel from .serializers import YourSerializer class EscalatedStatusListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.UpdateModelMixin): queryset = YourModel.objects.all() serializer_class = YourSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs)
URL配置同方案2,Swagger只会识别你手动实现的方法,不会生成重复条目。
内容的提问来源于stack exchange,提问作者Mohammed Yasin
相关产品推荐
相关产品推荐

