DRF自动生成OpenAPI文档

API schemas是非常有用的,可以帮助我们生成接口文档以及可与API交互的动态客户端。Django REST Framework支持自动生成OpenAPI schemas,但是目前支持的不是非常完善,需要手动修改的地方过多。在这里我们使用drf-spectacular这个第三方库来自动生成OpenAPI schemas.

drf-spectacular

安装,配置步骤可以参考drf-spectacular文档,下面简单的给出步骤。

安装和配置

  • 安装要求
Python >= 3.6
  Django (2.2, 3.1, 3.2)
  Django REST Framework (3.10, 3.11, 3.12)
  • 安装
pip3 install drf-spectacular[sidecar]
  • 注册
    在settings.py文件中,进行注册。
INSTALLED_APPS = [
  ...
  'drf_spectacular',
  'drf_spectacular_sidecar',

]

  • 配置
SPECTACULAR_SETTINGS = {
  'TITLE': 'Your Project API',
  'DESCRIPTION': 'Your project description',
  'VERSION': '1.0.0',
  'SWAGGER_UI_DIST': 'SIDECAR',  # shorthand to use the sidecar instead
  'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
  'REDOC_DIST': 'SIDECAR',
  }

  REST_FRAMEWORK = {
  # YOUR SETTINGS
  'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
  }

使用

  1. 直接生成yaml文件,然后配合swagger-ui来使用
python3 manage.py spectacular --file schema.yml
  1. 使用swagger-ui或redoc来展现
    一般情况,我们都是直接使用swagger-ui或者redoc来展现的。需要在urlpatterns中做如下的设置。
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
urlpatterns = [
    # YOUR PATTERNS
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    # Optional UI:
    path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

经过上面的基本配置,我们现在访问api/schema/swagger-ui/来查看swagger-ui风格的文档,如下所示:

生成fasta格式文件 Python flask生成api文档_OpenAPI


当你点击schema的时候,就会显示响应字段的描述,而且会明确告知你,描述是从XXX序列化器取得的。下面给出相应的序列化器代码。

class BookInfoSerializer(serializers.Serializer):
    """BookInfo序列化器"""
    id = serializers.IntegerField(label='书籍ID', read_only=True)
    name = serializers.CharField(label='名称', max_length=10)
    pub_date = serializers.DateField(label='发布日期')
    readcount = serializers.IntegerField(label='阅读量', min_value=0, required=False)
    commentcount = serializers.IntegerField(label='评论量', min_value=0, required=False)

我们看到的Schemas中的描述,description是来自于序列化器的文档字符串,而各个字段的title是来自于字段的label,带有*的意味着是必传的字段,除此之外,字段的其它描述是直接取自序列化器字段中的参数。

另外,对于该接口的描述也是直接来自文档字符串的内容。例如:

生成fasta格式文件 Python flask生成api文档_OpenAPI_02


下面给出视图的代码

class BookListView(GenericAPIView):
    """列表视图"""
    queryset = BookInfo.objects.all().order_by('id')
    serializer_class = BookInfoSerializer
    pagination_class = PageNum


    def get(self, request):
        """GET请求获取列表"""
        data = self.get_queryset()      # 获取查询结果集
        page = self.paginate_queryset(data)    #对查询结果集进行分页
        serializer = self.get_serializer(page, many=True)   # 序列化
        return Response(serializer.data)    # 返回值


    def post(self, request):
        """post请求新增"""
        data = request.data
        serializer = self.get_serializer(data=data)
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data, status=201)
        else:
            # 返回错误信息
            return Response({'msg': '保存失败'}, status=400)

对于HTTP Body中的内容,都在序列化器中描述了,但是对于URL参数,是默认没有描述的。我们需要手动修改,如下所示:

生成fasta格式文件 Python flask生成api文档_django_03


手动在代码中加入以下内容:

class BookView(GenericAPIView):
    """删改查视图"""
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    lookup_field = 'pk'
    lookup_url_kwarg = 'pk'

    @extend_schema(parameters=[OpenApiParameter(name='id', description='书籍唯一id', required=True, type=int, location=OpenApiParameter.PATH)])
    def get(self, request, pk):
        """根据id查询书籍详情"""
        obj = self.get_object()
        serializers = self.get_serializer(obj)

生成fasta格式文件 Python flask生成api文档_django_04


更多的信息,需要参考OpenAPI的规范,有一篇不错的文章,可以看看OpenAPI 规范摘要

drf-spectacular自动生成文档,很大程度上依赖于文档字符串以及queryset和serializer_class(DRF的APIView没有这两个属性,对于APIView自动生成文档有困难,当然你可以直接在APIView中定义这两个属性,但是会显得很奇怪。)

在视图集中使用

对于视图集而言,可以使用@extend_schema_view装饰器来直接装饰类。例如:

@extend_schema_view(
    list=extend_schema(description='列表'),
    create=extend_schema(description='新增'),
    retrieve=extend_schema(description='查询一个',parameters=[
    'id', OpenApiParameter("id", OpenApiTypes.INT, OpenApiParameter.PATH, description="书籍ID"),],),
    update=extend_schema(description='更新一个'),
    partial_update=extend_schema(description='部分更新'),
    destroy=extend_schema(description='删除一个'),
)
class BookModelViewSet(ModelViewSet):
    """书籍视图集"""
    queryset = BookInfo.objects.all().order_by('id')
    serializer_class = BookInfoSerializer
    pagination_class = PageNum
    lookup_field = 'id'
    lookup_url_kwarg = 'id'
    lookup_url_description = '书籍id'

上面这里方法和属性来自于下面的导入操作:

from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiExample, extend_schema_view, OpenApiTypes

关于更多的使用方法,请参考文档