> 백엔드 개발 > 파이썬 튜토리얼 > 관리 인터페이스 문서를 살펴보세요.

관리 인터페이스 문서를 살펴보세요.

coldplay.xixi
풀어 주다: 2020-09-04 16:30:00
앞으로
3556명이 탐색했습니다.

관리 인터페이스 문서를 살펴보세요.

관련 학습 권장사항: python tutorial

대부분의 경우 개발된 인터페이스는 인터페이스를 개발한 사람이 사용하지 않으므로 인터페이스 문서가 없으면 다른 사람들은 어떤 인터페이스를 사용할 수 있는지 알 수 없습니다. 인터페이스의 URL을 알더라도 해당 인터페이스에 어떤 매개변수가 필요한지 알기 어렵습니다. 이러한 매개변수를 알더라도 해당 매개변수의 의미를 이해하지 못할 수도 있습니다. 따라서 인터페이스 문서는 프로젝트의 필수 구성이 되어야 합니다.

인터페이스 문서를 작성하는 방법에는 여러 가지가 있습니다. 가장 간단하고 직접적인 방법은 메모장이나 워드 문서를 열고 인터페이스의 세부 사항과 사용법을 적어 두는 것입니다. 이것은 간단하지만 단점도 분명합니다. 첫째, 설명 텍스트를 많이 작성해야 하기 때문에 매우 지루하지만 실제로 이 정보는 코드에 반영되어 있어 자연어를 사용하여 작성하는 것과 약간 비슷합니다. 두 번째, 인터페이스가 업데이트되면 인터페이스 문서를 동기식으로 수동으로 업데이트해야 하며, 개발자는 이를 쉽게 잊어버릴 수 있으며, 이로 인해 인터페이스 문서의 내용과 인터페이스의 실제 기능이 일치하지 않게 됩니다.

실제로 많은 인터페이스 정보가 코드에 반영되기 때문에 사람들은 작성된 코드에서 직접 관련 정보를 자동으로 추출하여 문서를 생성할 수 있는지 자연스럽게 생각하게 됩니다. 위에서 언급한 대로 자동으로 업데이트됩니다. 두 가지 문제가 모두 해결될 수 있습니다.

물론 인터페이스 문서 작성은 문학적 창작이 아닙니다. 작성된 코드에서 직접 정보를 자동으로 추출하여 문서를 생성하려면 표준 문서 형식이 있어야 합니다. 그렇지 않으면 도구가 코드에서 어떤 정보를 추출할지 알 수 없습니다. 정보 추출한 후 정보를 어떻게 정리해야 할지 모르겠습니다.

모든 사람의 노력을 통해 이제 성숙한 인터페이스 문서 표준과 생성 도구가 많이 있습니다. 그중 OpenAPI 사양은 널리 수용되고 사용되는 표준입니다. 블로그 인터페이스에서 사용되는 문서 자동화 도구도 OpenAPI 표준을 기반으로 합니다. 정보는 문서에서 추출된 다음 OpenAPI의 표준 형식으로 구성됩니다.

팁:

OpenAPI와 관련된 더 친숙한 용어는 swagger입니다. Swagger는 일련의 무료 오픈 소스 OpenAPI 관련 도구를 제공하며 이를 뒷받침하는 회사는 코드 품질 도구 개발 업계의 선두주자로 알려진 SMARTBEAR입니다.

OpenAPI 소개

인터페이스 문서는 문학 작품이 아니며 기본적으로 필요한 내용이 정해져 있습니다. 예를 들어 RESTful 인터페이스의 경우 호출을 완료하려면 다음 주요 정보만 알면 됩니다. 결과적으로 이 정보는 완전한 RESTful 스타일 인터페이스를 정의할 수 있습니다.

  • 요청된 HTTP 메서드 및 URL.
  • 수신된 매개변수(URL의 경로 매개변수 및 쿼리 매개변수, HTTP 요청 헤더 매개변수, HTTP 요청 본문 및 기타 매개변수 포함)
  • 인터페이스에서 반환된 콘텐츠입니다.

OpenAPI는 위의 정보를 표준화하여 OpenAPI 사양을 제안했습니다. 문서 내용이 이 표준을 충족하는 한 OpenAPI 도구는 이를 처리할 수 있습니다. 예를 들어 시각적 문서 도구는 문서 내용을 읽고 HTML 형식의 문서를 생성할 수 있습니다. .

참고:

OpenAPI 사양의 최신 버전은 현재 3개이지만 대부분의 도구는 현재 가장 좋은 2개를 지원하며 튜토리얼에 사용된 라이브러리는 2개만 지원합니다.

drf-yasg

drf-yasg는 django-rest-framework 프레임워크로 작성된 코드에서 인터페이스 정보를 자동으로 추출하여 OpenAPI 표준을 준수하는 문서를 생성할 수 있는 django용 타사 애플리케이션입니다. 이를 사용하여 블로그 애플리케이션에 대한 인터페이스 문서를 생성할 것입니다.

첫 번째 단계는 물론 drf-yasg를 설치하고, 프로젝트 루트 디렉터리에 들어가서 다음 명령을 실행하는 것입니다:

Command Tab

Linux/macOS
$ pipenv install drf-yasg复制代码
로그인 후 복사
Windows
...\> pipenv install drf-yasg复制代码
로그인 후 복사

그런 다음 drf-yasg를 INSTALLED_APPS 구성 항목에 추가합니다: INSTALLED_APPS 配置项中:

# filename="blogproject/settings/common.py"INSTALLED_APPS = [    # 其它已添加的应用...
        "pure_pagination",  # 分页
    "haystack",  # 搜索
    "drf_yasg", # 文档]复制代码
로그인 후 복사

接着使用 drf_yasg 提供的函数来创建一个 django 视图,这个视图将返回 HTML 格式的文档内容,这样我们就可以直接在浏览器查看到博客的接口文档:

# filename="blogproject/urls.py"from django.urls import include, path, re_pathfrom drf_yasg import openapifrom drf_yasg.views import get_schema_viewfrom rest_framework import permissions, routers


schema_view = get_schema_view(
    openapi.Info(
        title="HelloDjango REST framework tutorial API",
        default_version="v1",
        description="HelloDjango REST framework tutorial AP",
        terms_of_service="",
        contact=openapi.Contact(email="zmrenwu@163.com"),
        license=openapi.License(name="GPLv3 License"),
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [    # 其它已注册的 URL 模式...
  
    # 文档
    re_path(        r"swagger(?P<format>\.json|\.yaml)",
        schema_view.without_ui(cache_timeout=0),
        name="schema-json",
    ),
    path(        "swagger/",
        schema_view.with_ui("swagger", cache_timeout=0),
        name="schema-swagger-ui",
    ),
    path("redoc/", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"),
]复制代码
로그인 후 복사

只需要使用 get_schema_view

Linux/macOS
$ pipenv run python manage.py runserver复制代码
로그인 후 복사

그런 다음 drf_yasg에서 제공하는 기능을 사용하여 django 뷰를 만듭니다. 이 뷰는 문서 콘텐츠를 HTML 형식으로 반환하므로 브라우저에서 직접 블로그의 인터페이스 문서를 볼 수 있습니다.

Windows
...\> pipenv run python manage.py runserver复制代码
로그인 후 복사

get_schema_view<를 사용하세요. /code> 문서 보기가 생성될 수 있으며 이 보기 기능을 4개의 URL에 매핑합니다. <h3 data-id="heading-3"></h3>이제 프로젝트 루트 디렉토리에 들어가서 개발 서버를 시작하세요: <p></p>Command Tab🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"># filename=&quot;blog/views.py&quot;class ApiVersionTestViewSet(viewsets.ViewSet): # pragma: no cover swagger_schema = None复制代码</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"># filename=&quot;blog/views.py&quot;from django.utils.decorators import method_decoratorfrom drf_yasg.utils import swagger_auto_schema@method_decorator( name=&quot;retrieve&quot;, decorator=swagger_auto_schema( auto_schema=None, ), )class PostSearchView(HaystackViewSet): index_models = [Post] serializer_class = PostHaystackSerializer throttle_classes = [PostSearchAnonRateThrottle]复制代码</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜 그런 다음 http://127.0.0.1:8000/swagger/ 또는 http://127.0.0.1:8000/redoc/를 방문하세요. drf-yasg에 의해 자동으로 생성된 HTML 형식의 인터페이스 문서를 볼 수 있습니다. http://127.0.0.1:8000/swagger.json 또는 http://127.0.0.1:8000/swagger.yaml을 방문하면 원본 OpenAPI 표준 문서를 볼 수 있으며 이 표준을 기반으로 swagger와 redoc이 모두 생성됩니다. 문서. 시각적 UI 인터페이스. 🎜<h2 data-id="heading-4">完善文档</h2><p>drf-yasg 毕竟不是使用人工智能开发的,即使是使用人工智能,也很难做到 100% 的正确,毕竟由人类写的代码可能是千变万化的,工具无法预料到所有可能的情况,一旦它遇到无法处理的地方,自动生成的文档就可能出错,或者生成的内容不符合我们的预期。</p><p>我们不妨访问 http://127.0.0.1:8000/swagger/ 先来看看没做任何定制化之前生成的效果。可以看到内容大体上是正确的,接口基本上都罗列了出来,但是仔细检查各个接口的内容,就会发现一些问题:</p><ol><li>GET /api-version/test/ 这个接口是我们用来测试的,不希望它显示在文档里。</li><li>基本上没有任何描述信息来说明这个接口的功能。</li><li>接口的部分参数也没有描述信息,可能会让接口的使用者无法知道其准确含义。</li><li>GET /posts/archive/dates/ 这个接口显示的参数是错误的,它不应该接受任何查询参数,接口响应参数也是错误的。</li><li>GET /posts/{id}/comments/ 这个接口应该还支持分页查询的参数,但生成的文档中没有列出,接口响应参数也是错误的,正确的应该是一个分页后的评论列表,但文档中是单个评论对象。</li><li>GET /search/ 没有列出搜索参数 text。</li><li>多出一个 GET /search/{id}/ 接口,这个接口我们并不需要其被使用,因此也无需在文档列出。</li></ol><p>接下来我们就一个个地来解决上面的问题,只需要稍加改变一下 drf-yasg 的默认行为,就能够生成我们预期的文档内容。</p><h3 data-id="heading-5">隐藏不需要的接口</h3><p>首先将第 1 点和第 7 点提到的不需要的接口从自动生成的文档中隐藏。</p><p>对于 GET /api-version/test/ 这个接口,它对应的视图集是 <code>ApiVersionTestViewSet,给这个视图集添加一个 swagger_schema 类属性,将值设为 None,这样 drf-yasg 就知道忽略这个视图集对应的接口了。

# filename="blog/views.py"class ApiVersionTestViewSet(viewsets.ViewSet):  # pragma: no cover
    swagger_schema = None复制代码
로그인 후 복사
로그인 후 복사

隐藏 GET /search/{id}/ 接口的方式稍微有点不同,因为对应的视图集 PostSearchView 不只这一个接口,上面的处理方式会把整个视图集的接口都隐藏,我们需要想办法隐藏指定 action 对应的接口。

drf-yasg 提供了一个 swagger_auto_schema 装饰器来装饰视图,只需要为装饰器设置 auto_shema=None 就可以让 drf-yasg 忽略掉被装饰的视图,具体用法如下:

# filename="blog/views.py"from django.utils.decorators import method_decoratorfrom drf_yasg.utils import swagger_auto_schema@method_decorator(
    name="retrieve",
    decorator=swagger_auto_schema(
        auto_schema=None,
    ),
)class PostSearchView(HaystackViewSet):
    index_models = [Post]
    serializer_class = PostHaystackSerializer
    throttle_classes = [PostSearchAnonRateThrottle]复制代码
로그인 후 복사
로그인 후 복사

需要隐藏的接口对应 retrieve 这个 action,因此我们装饰的是这个方法。因为 PostSearchView 继承自 HaystackViewSet,在代码中并没有显示地定义 retrieve 这个方法,而是从父类继承而来,所以我们借助 django 提供的辅助函数 method_decorator 非侵入式地为类的某个方法添加装饰器。

现在访问接口文档地址,可以看到不需要的接口已经从文档中隐藏了。

添加接口功能描述信息

接下来解决第 2 个问题,为接口添加必要的功能描述。drf-yasg 支持从视图的 docstring 解析接口对应的描述信息,只要符合指定的格式即可。

先来一个简单例子,为 GET /categories/ 这个接口添加描述信息,找到 CategoryViewSet 视图集,添加格式化的 docstring:

# filename="blog/views.py"class CategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    博客文章分类视图集

    list:
    返回博客文章分类列表
    """复制代码
로그인 후 복사

CategoryViewSet 视图集就一个接口,对应的 action 是 list,因此 docstring 的格式就像上面那样,文档中的效果如下:

관리 인터페이스 문서를 살펴보세요.

可以看到接口请求 URL 下方多出了我们写的描述内容。其它一些简单的接口都可以用这种方式来添加功能描述信息,留作练习的内容交给你自己了。

tip 描述的内容还支持 Markdown 格式,这样我们可以根据需要写出格式丰富的内容。

对于稍微复杂一点视图集,例如 PostViewSet,这个视图集含有多个 action 对应多个接口,功能描述信息的格式差不多是一样的,关键点是指明每个 action 对应的内容:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """
    博客文章视图集

    list:
    返回博客文章列表

    retrieve:
    返回博客文章详情

    list_comments:
    返回博客文章下的评论列表

    list_archive_dates:
    返回博客文章归档日期列表
    """复制代码
로그인 후 복사

添加参数说明

接着我们来完善接口的参数说明文档。通过查看自动生成的文档中各个接口的参数,发现主要有这么几个问题:

  • 有些参数没有说明,无法准确知道其含义。
  • 有些接口该有的参数,文档中没有列出。
  • 有些接口不该有的参数,文档中却列出来了。

例如我们可以看到 GET /posts/{id}/ 这个接口的响应参数,其中大部分有中文信息的描述,我们可以推断,这些说明都是 drf-yasg 自动从定义在 Post 模型各字段的 verbose_name 参数的值提取的。其中 toc 和 body_html 因为不是 Post 中定义的字段,所以 drf-yasg 无法知道关于这两个字段的说明。

drf-yasg 是如何知道这个接口会返回哪些响应参数的呢?原理是 drf-yasg 会尝试去解析接口对应的序列化器(Serializer),从序列化器中提取出对应的请求和响应字段(如果序列化器中找不到,它会进一步去序列化器关联的模型中找),因此我们就可以给序列化器中定义的字段添加说明信息。例如我们来给 toc 和 body_html 添加 label 参数:

# filename="blog/views.py"class PostRetrieveSerializer(serializers.ModelSerializer):
    toc = serializers.CharField(label="文章目录")
    body_html = serializers.CharField(label="文章内容")复制代码
로그인 후 복사

访问接口文档地址,找到对应的接口,可以看到文档中这两个字段添加了对应的说明信息,还可以通过 help_text(Model 中的字段也支持这个参数)来添加更为详细的描述,例如:

# filename="blog/serializers.py"class PostRetrieveSerializer(serializers.ModelSerializer):
    toc = serializers.CharField(label="文章目录", help_text="HTML 格式,每个目录条目均由 li 标签包裹。")
    body_html = serializers.CharField(
        label="文章内容", help_text="HTML 格式,从 `body` 字段解析而来。"
    )复制代码
로그인 후 복사

这样两个字段的含义就非常清晰了,效果如下:

관리 인터페이스 문서를 살펴보세요.

其它一些没有说明信息的字段都可以根据这种方式来添加,只需要找到文档中的参数在代码中对应的来源字段就可以了。除了在序列化器(Serializer)、模型(Model)里面添加。查询过滤参数也是可以这样设置的,例如先来看一下 GET /posts/ 的参数:

관리 인터페이스 문서를 살펴보세요.

可以看到用来过滤文章列表的参数都没有说明,这些字段都定义在 PostFilter 中,我们来改一下代码,添加必要的说明信息后再去文档中看看效果吧!

# filename="blog/filters.py"from .models import Category, Post, Tagclass PostFilter(drf_filters.FilterSet):
    created_year = drf_filters.NumberFilter(
        field_name="created_time", lookup_expr="year", help_text="根据文章发表年份过滤文章列表"
    )
    created_month = drf_filters.NumberFilter(
        field_name="created_time", lookup_expr="month", help_text="根据文章发表月份过滤文章列表"
    )
    category = drf_filters.ModelChoiceFilter(
        queryset=Category.objects.all(),
        help_text="根据分类过滤文章列表",
    )
    tags = drf_filters.ModelMultipleChoiceFilter(
        queryset=Tag.objects.all(),
        help_text="根据标签过滤文章列表",
    )    class Meta:
        model = Post
        fields = ["category", "tags", "created_year", "created_month"]复制代码
로그인 후 복사

接着我们来看 GET /posts/archive/dates/ 和 GET /posts/{id}/comments/ 这两个接口。前者文档中显示了一些错误的参数,后者本应该有分页参数,但是文档却没有列出。

先来看 GET /posts/archive/dates/,它对应的 action 是 list_archive_dates,由于 action 默认会从它所在的视图集中继承一些属性,而 drf-yasg 会从这些属性去解析接口支持的参数,例如视图集设置了 filterset_class = PostFilterpagination_class=PageNumberPagination(虽然不在视图集中显示定义,但在全局进行了配置),在解析 list_archive_dates 的参数时,drf-yasg 错误地解析到了从视图集继承来的 PostFilterPageNumberPagination,所以就把这两个类中定义的参数也包含进文档了。

知道了原因,解决方法也就有了,在 list_archive_dates action 中把这两个属性设为 None,覆盖掉视图集中的默认设置:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):  @action(
        # ...
        filter_backends=None, # 将 filter_backends 设为 None,filterset_class 也就不起作用了。
        pagination_class=None,
    )    def list_archive_dates(self, request, *args, **kwargs):
        # ...复制代码
로그인 후 복사

再来看看这个接口,就没有那些错误的参数了。

接着处理 GET /posts/{id}/comments/ 接口,我们需要文档列出分页参数。这个接口对应的 action 是 list_comment。从上面的分析来看,这个 action 明明已经指定了 pagination_class=LimitOffsetPagination,为什么 drf-yasg 无法自动检测到分页参数呢?原因是这个 action 设置了 detail=True。当 detial=True 时,drf-yasg 会将这个 action 对应的接口看做获取单个资源的接口,因此它认为分页是不需要的。但实际上我们对这个接口进行了定制,它返回的其实是评论列表。解决办法是应该告诉 drf-yasg,这个接口返回的是列表结果,请去解析列表接口相关的一些参数:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):    @action(
        methods=["GET"],
        detail=True,        # ...
        suffix="List",  # 将这个 action 返回的结果标记为列表,否则 drf-yasg 会根据 detail=True 误判为这是返回单个资源的接口
        pagination_class=LimitOffsetPagination,
        serializer_class=CommentSerializer,
    )    def list_comments(self, request, *args, **kwargs):
        # ...复制代码
로그인 후 복사

但是 drf-yasg 还是不够聪明,当它去解析列表接口可能的参数时,顺便又把 PostFilter 中的字段也一并解析了,这是用来过滤博客文章的,显然不能用于过滤评论列表,我们需要将这些无关参数移除,解决方法在处理 GET /posts/archive/dates/ 接口时就讲过了,把 filter_backends 设置成 None 就可以了。

更正错误的响应参数

仔细看生成的接口文档,发现有 2 个接口的返回内容是错误的。

一是 GET /posts/{id}/comments/,最初我们发现这个接口文档的响应是一个单一的评论对象,原因我们上面也分析了,drf-yasg 根据 detail=True 误地将其作为返回单一资源的接口处理了。随着为其添加更多信息,告诉 drf-yasg 这是一个返回资源列表的接口,问题也就顺便解决了。

二是 GET /posts/archive/dates/,这个接口的返回内容应该是一个日期列表,但是文档中显示的竟然是博客文章列表。drf-yasg 推断的响应类型是正确的,但内容不对。原因也很明显,这个接口对应的 action 是 list_archive_dates,drf-yasg 在这个 action 中没有找到解析响应结果的序列化器(Serializer),所以它跑去视图集 PostViewSet 中去找了,结果找到了 PostListSerializer,然后把这个当成了接口返回的内容进行解析了。

由于这个接口返回的仅仅是一个简单的日期列表,并不涉及到序列化器,因此这里我们不使用指定 serializer_class 属性值的方式,而是使用 swagger_auto_schema 装饰器,直接告诉 drf-yasg 接口返回的响应:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):        @swagger_auto_schema(responses={200: "归档日期列表,时间倒序排列。例如:[&#39;2020-08&#39;, &#39;2020-06&#39;]"})    @action(
        methods=["GET"],
        detail=False,
        url_path="archive/dates",
        url_name="archive-date",
        filter_backends=None,
        pagination_class=None,
    )    def list_archive_dates(self, request, *args, **kwargs):
        # ...复制代码
로그인 후 복사

responses 参数的值是一个字典,字典的键是 HTTP 响应码,值可以是一个序列化器,这样 drf-yasg 会拿这个序列化器去解析接口响应的参数;也可以是一个字符串,drf-yasg 会把字符串直接当做接口响应结果写入文档中。看看修改后的效果:

관리 인터페이스 문서를 살펴보세요.

至此,我们就有了一套比较完善的博客接口文档了,而且大部分内容均由 drf-yasg 为我们自动生成,省去了不少手写文档的麻烦。

小贴士:

drf-yasg 的官方文档对于这个库的使用方法写的不是很清晰,这篇文章中列出的一些用法都是从源码中看出来的。如果你在使用过程中遇到了问题,首先尝试分析问题的原因,然后顺藤摸瓜去找到相关的源码,看看库的内部是如何处理你所遇到的问题的,这样就可以针对性地给出解决方案了,这篇教程中列出的很多问题以及最后给出的解决方案,都是使用的这种方式。

想了解更多编程学习,敬请关注php培训栏目!

위 내용은 관리 인터페이스 문서를 살펴보세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.im
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿