Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 中文字幕日韩精品亚洲七区,亚洲一区二区三区福利在线,先锋影音亚洲

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          第 16 篇:別再手動(dòng)管理接口文檔了

          第 16 篇:別再手動(dòng)管理接口文檔了

          者:HelloGitHub-追夢(mèng)人物

          大多數(shù)情況下,開(kāi)發(fā)的接口都不是給開(kāi)發(fā)這個(gè)接口的人用的,所以如果沒(méi)有接口文檔,別人就無(wú)法有哪些接口可以調(diào)用,即使知道了接口的 URL,也很難知道接口需要哪些參數(shù),即使知道了這些參數(shù),也可能無(wú)法理解這些參數(shù)的含義。因此接口文檔應(yīng)該是項(xiàng)目必不可少的配置。

          編寫接口文檔有很多種方式,最為簡(jiǎn)單直接的方式就是打開(kāi)一個(gè)記事本或者 word 文檔,將接口的詳細(xì)信息和用法寫下來(lái),別人就可以參考這個(gè)文檔來(lái)調(diào)用接口。這樣做雖然簡(jiǎn)單,但弊端也很明顯:一是需要寫大量的描述文字,非??菰铮鋵?shí)這些信息在代碼中已有體現(xiàn),有點(diǎn)像是使用自然語(yǔ)言又把代碼寫了一遍;二是一旦接口有了更新,就必須手動(dòng)同步更新接口文檔,開(kāi)發(fā)人員很容易搞忘這件事,導(dǎo)致接口文檔的內(nèi)容和接口的實(shí)際功能不一致。

          因?yàn)楹芏嘟涌诘男畔⑵鋵?shí)在代碼中已有體現(xiàn),人們自然而然就想到能否直接從寫好的代碼中自動(dòng)提取相關(guān)信息來(lái)生成文檔,這樣改了代碼,接口文檔也會(huì)自動(dòng)更新,上面說(shuō)的兩個(gè)問(wèn)題就都可以解決了。

          當(dāng)然寫接口文檔不是搞文學(xué)創(chuàng)作,為了直接從寫好的代碼中自動(dòng)提取信息來(lái)生成文檔,就必須要有一套標(biāo)準(zhǔn)的文檔格式,否則工具無(wú)法知道要從代碼中提取出哪些信息,信息提取之后,也不知道該如何組織這些信息。

          經(jīng)過(guò)大家的努力,現(xiàn)在已經(jīng)有了很多成熟的接口文檔標(biāo)準(zhǔn)和生成工具,其中 OpenAPI Specification[1] 就是一個(gè)被廣泛接收和使用的標(biāo)準(zhǔn),我們博客接口使用的文檔自動(dòng)化工具,也會(huì)基于 OpenAPI 標(biāo)準(zhǔn)從代碼中提取文檔信息,然后組織為 OpenAPI 的標(biāo)準(zhǔn)格式。

          小貼士:

          大家更為熟悉的,和 OpenAPI 相關(guān)的一個(gè)名詞是 swagger。Swagger[2] 提供一系列免費(fèi)開(kāi)源的 OpenAPI 相關(guān)的工具,他們背后的公司是 SMARTBEAR[3],號(hào)稱 code quality tools 開(kāi)發(fā)行業(yè)的領(lǐng)導(dǎo)者。

          OpenAPI 介紹

          接口文檔不是文學(xué)作品,它所需要的內(nèi)容基本都是固定的。例如對(duì)一個(gè) RESTful 風(fēng)格的接口來(lái)說(shuō),只需要知道以下這些關(guān)鍵的信息就足夠完成對(duì)它的調(diào)用了。反過(guò)來(lái),這些信息也就可以定義一個(gè)完整的 RESTful 風(fēng)格的接口:

          • 請(qǐng)求的 HTTP 方法和 URL。
          • 接收的參數(shù)(包括 URL 中的路徑參數(shù)、查詢參數(shù);HTTP 請(qǐng)求頭的參數(shù);HTTP 請(qǐng)求體等參數(shù))。
          • 接口返回的內(nèi)容。

          OpenAPI 對(duì)以上信息進(jìn)行了標(biāo)準(zhǔn)化,從而提出了 OpenAPI specification[4],只要文檔內(nèi)容符合這個(gè)標(biāo)準(zhǔn),OpenAPI 工具就可以對(duì)它進(jìn)行處理,例如可視化文檔工具就可以讀取文檔內(nèi)容生成 HTML 格式的文檔。

          注意:

          OpenAPI specification 目前最新版本是 3,但目前大部分工具對(duì) 2 的支持最好,教程中使用的庫(kù)僅支持 2。

          drf-yasg

          drf-yasg[5] 是一個(gè) django 的第三方應(yīng)用,它可以從 django-rest-framework 框架編寫的代碼中自動(dòng)提取接口信息來(lái)生成符合 OpenAPI 標(biāo)準(zhǔn)的文檔。我們將使用它來(lái)生成博客應(yīng)用的接口文檔。

          第一步當(dāng)然是安裝 drf-yasg,進(jìn)入項(xiàng)目根目錄,運(yùn)行命令 :

          Command Tab

          Linux/macOS
          $ pipenv install drf-yasg
          
          Windows
          ...\> pipenv install drf-yasg
          

          然后將 drf-yasg 添加到 INSTALLED_APPS 配置項(xiàng)中:

          # filename="blogproject/settings/common.py"
          INSTALLED_APPS = [
              # 其它已添加的應(yīng)用...
            "pure_pagination",  # 分頁(yè)
              "haystack",  # 搜索
              "drf_yasg", # 文檔
          ]
          

          接著使用 drf_yasg 提供的函數(shù)來(lái)創(chuàng)建一個(gè) django 視圖,這個(gè)視圖將返回 HTML 格式的文檔內(nèi)容,這樣我們就可以直接在瀏覽器查看到博客的接口文檔:

          # filename="blogproject/urls.py"
          from django.urls import include, path, re_path
          from drf_yasg import openapi
          from drf_yasg.views import get_schema_view
          from 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 = [
             # 其它已注冊(cè)的 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 就可以生成一個(gè)文檔視圖,然后我們將這個(gè)視圖函數(shù)映射到了 4 個(gè) URL。

          現(xiàn)在進(jìn)入項(xiàng)目根目錄,啟動(dòng)開(kāi)發(fā)服務(wù)器:

          Command Tab

          Linux/macOS
          $ pipenv run python manage.py runserver
          
          Windows
          ...\> pipenv run python manage.py runserver
          

          然后訪問(wèn) http://127.0.0.1:8000/swagger/ 或者 http://127.0.0.1:8000/redoc/,你就可以看到 drf-yasg 自動(dòng)生成的 HTML 格式的接口文檔了。如果訪問(wèn) http://127.0.0.1:8000/swagger.json 或者 http://127.0.0.1:8000/swagger.yaml 就可以看到原始的 OpenAPI 標(biāo)準(zhǔn)文檔,swagger 和 redoc 都是基于這個(gè)標(biāo)準(zhǔn)文檔來(lái)生成可視化的 UI 界面的。

          完善文檔

          drf-yasg 畢竟不是使用人工智能開(kāi)發(fā)的,即使是使用人工智能,也很難做到 100% 的正確,畢竟由人類寫的代碼可能是千變?nèi)f化的,工具無(wú)法預(yù)料到所有可能的情況,一旦它遇到無(wú)法處理的地方,自動(dòng)生成的文檔就可能出錯(cuò),或者生成的內(nèi)容不符合我們的預(yù)期。

          我們不妨訪問(wèn) http://127.0.0.1:8000/swagger/ 先來(lái)看看沒(méi)做任何定制化之前生成的效果。可以看到內(nèi)容大體上是正確的,接口基本上都羅列了出來(lái),但是仔細(xì)檢查各個(gè)接口的內(nèi)容,就會(huì)發(fā)現(xiàn)一些問(wèn)題:

          1. GET /api-version/test/ 這個(gè)接口是我們用來(lái)測(cè)試的,不希望它顯示在文檔里。
          2. 基本上沒(méi)有任何描述信息來(lái)說(shuō)明這個(gè)接口的功能。
          3. 接口的部分參數(shù)也沒(méi)有描述信息,可能會(huì)讓接口的使用者無(wú)法知道其準(zhǔn)確含義。
          4. GET /posts/archive/dates/ 這個(gè)接口顯示的參數(shù)是錯(cuò)誤的,它不應(yīng)該接受任何查詢參數(shù),接口響應(yīng)參數(shù)也是錯(cuò)誤的。
          5. GET /posts/{id}/comments/ 這個(gè)接口應(yīng)該還支持分頁(yè)查詢的參數(shù),但生成的文檔中沒(méi)有列出,接口響應(yīng)參數(shù)也是錯(cuò)誤的,正確的應(yīng)該是一個(gè)分頁(yè)后的評(píng)論列表,但文檔中是單個(gè)評(píng)論對(duì)象。
          6. GET /search/ 沒(méi)有列出搜索參數(shù) text。
          7. 多出一個(gè) GET /search/{id}/ 接口,這個(gè)接口我們并不需要其被使用,因此也無(wú)需在文檔列出。

          接下來(lái)我們就一個(gè)個(gè)地來(lái)解決上面的問(wèn)題,只需要稍加改變一下 drf-yasg 的默認(rèn)行為,就能夠生成我們預(yù)期的文檔內(nèi)容。

          隱藏不需要的接口

          首先將第 1 點(diǎn)和第 7 點(diǎn)提到的不需要的接口從自動(dòng)生成的文檔中隱藏。

          對(duì)于 GET /api-version/test/ 這個(gè)接口,它對(duì)應(yīng)的視圖集是 ApiVersionTestViewSet,給這個(gè)視圖集添加一個(gè) swagger_schema 類屬性,將值設(shè)為 None,這樣 drf-yasg 就知道忽略這個(gè)視圖集對(duì)應(yīng)的接口了。

          # filename="blog/views.py"
          class ApiVersionTestViewSet(viewsets.ViewSet):  # pragma: no cover
              swagger_schema = None
          

          隱藏 GET /search/{id}/ 接口的方式稍微有點(diǎn)不同,因?yàn)閷?duì)應(yīng)的視圖集 PostSearchView 不只這一個(gè)接口,上面的處理方式會(huì)把整個(gè)視圖集的接口都隱藏,我們需要想辦法隱藏指定 action 對(duì)應(yīng)的接口。

          drf-yasg 提供了一個(gè) swagger_auto_schema 裝飾器來(lái)裝飾視圖,只需要為裝飾器設(shè)置 auto_shema=None 就可以讓 drf-yasg 忽略掉被裝飾的視圖,具體用法如下:

          # filename="blog/views.py"
          from django.utils.decorators import method_decorator
          from 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]
          

          需要隱藏的接口對(duì)應(yīng) retrieve 這個(gè) action,因此我們裝飾的是這個(gè)方法。因?yàn)?PostSearchView 繼承自 HaystackViewSet,在代碼中并沒(méi)有顯示地定義 retrieve 這個(gè)方法,而是從父類繼承而來(lái),所以我們借助 django 提供的輔助函數(shù) method_decorator 非侵入式地為類的某個(gè)方法添加裝飾器。

          現(xiàn)在訪問(wèn)接口文檔地址,可以看到不需要的接口已經(jīng)從文檔中隱藏了。

          添加接口功能描述信息

          接下來(lái)解決第 2 個(gè)問(wèn)題,為接口添加必要的功能描述。drf-yasg 支持從視圖的 docstring 解析接口對(duì)應(yīng)的描述信息,只要符合指定的格式即可。

          先來(lái)一個(gè)簡(jiǎn)單例子,為 GET /categories/ 這個(gè)接口添加描述信息,找到 CategoryViewSet 視圖集,添加格式化的 docstring:

          # filename="blog/views.py"
          class CategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
              """
              博客文章分類視圖集
          
              list:
              返回博客文章分類列表
              """
          

          CategoryViewSet 視圖集就一個(gè)接口,對(duì)應(yīng)的 action 是 list,因此 docstring 的格式就像上面那樣,文檔中的效果如下:

          可以看到接口請(qǐng)求 URL 下方多出了我們寫的描述內(nèi)容。其它一些簡(jiǎn)單的接口都可以用這種方式來(lái)添加功能描述信息,留作練習(xí)的內(nèi)容交給你自己了。

          tip 描述的內(nèi)容還支持 Markdown 格式,這樣我們可以根據(jù)需要寫出格式豐富的內(nèi)容。

          對(duì)于稍微復(fù)雜一點(diǎn)視圖集,例如 PostViewSet,這個(gè)視圖集含有多個(gè) action 對(duì)應(yīng)多個(gè)接口,功能描述信息的格式差不多是一樣的,關(guān)鍵點(diǎn)是指明每個(gè) action 對(duì)應(yīng)的內(nèi)容:

          # filename="blog/views.py"
          class PostViewSet(
              mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
          ):
              """
              博客文章視圖集
          
              list:
              返回博客文章列表
          
              retrieve:
              返回博客文章詳情
          
              list_comments:
              返回博客文章下的評(píng)論列表
          
              list_archive_dates:
              返回博客文章歸檔日期列表
              """
          

          添加參數(shù)說(shuō)明

          接著我們來(lái)完善接口的參數(shù)說(shuō)明文檔。通過(guò)查看自動(dòng)生成的文檔中各個(gè)接口的參數(shù),發(fā)現(xiàn)主要有這么幾個(gè)問(wèn)題:

          • 有些參數(shù)沒(méi)有說(shuō)明,無(wú)法準(zhǔn)確知道其含義。
          • 有些接口該有的參數(shù),文檔中沒(méi)有列出。
          • 有些接口不該有的參數(shù),文檔中卻列出來(lái)了。

          例如我們可以看到 GET /posts/{id}/ 這個(gè)接口的響應(yīng)參數(shù),其中大部分有中文信息的描述,我們可以推斷,這些說(shuō)明都是 drf-yasg 自動(dòng)從定義在 Post 模型各字段的 verbose_name 參數(shù)的值提取的。其中 toc 和 body_html 因?yàn)椴皇?Post 中定義的字段,所以 drf-yasg 無(wú)法知道關(guān)于這兩個(gè)字段的說(shuō)明。

          drf-yasg 是如何知道這個(gè)接口會(huì)返回哪些響應(yīng)參數(shù)的呢?原理是 drf-yasg 會(huì)嘗試去解析接口對(duì)應(yīng)的序列化器(Serializer),從序列化器中提取出對(duì)應(yīng)的請(qǐng)求和響應(yīng)字段(如果序列化器中找不到,它會(huì)進(jìn)一步去序列化器關(guān)聯(lián)的模型中找),因此我們就可以給序列化器中定義的字段添加說(shuō)明信息。例如我們來(lái)給 toc 和 body_html 添加 label 參數(shù):

          # filename="blog/views.py"
          class PostRetrieveSerializer(serializers.ModelSerializer):
             toc = serializers.CharField(label="文章目錄")
              body_html = serializers.CharField(label="文章內(nèi)容")
          

          訪問(wèn)接口文檔地址,找到對(duì)應(yīng)的接口,可以看到文檔中這兩個(gè)字段添加了對(duì)應(yīng)的說(shuō)明信息,還可以通過(guò) help_text(Model 中的字段也支持這個(gè)參數(shù))來(lái)添加更為詳細(xì)的描述,例如:

          # filename="blog/serializers.py"
          class PostRetrieveSerializer(serializers.ModelSerializer):
             toc = serializers.CharField(label="文章目錄", help_text="HTML 格式,每個(gè)目錄條目均由 li 標(biāo)簽包裹。")
              body_html = serializers.CharField(
                  label="文章內(nèi)容", help_text="HTML 格式,從 `body` 字段解析而來(lái)。"
              )
          

          這樣兩個(gè)字段的含義就非常清晰了,效果如下:

          其它一些沒(méi)有說(shuō)明信息的字段都可以根據(jù)這種方式來(lái)添加,只需要找到文檔中的參數(shù)在代碼中對(duì)應(yīng)的來(lái)源字段就可以了。除了在序列化器(Serializer)、模型(Model)里面添加。查詢過(guò)濾參數(shù)也是可以這樣設(shè)置的,例如先來(lái)看一下 GET /posts/ 的參數(shù):

          可以看到用來(lái)過(guò)濾文章列表的參數(shù)都沒(méi)有說(shuō)明,這些字段都定義在 PostFilter 中,我們來(lái)改一下代碼,添加必要的說(shuō)明信息后再去文檔中看看效果吧!

          # filename="blog/filters.py"
          from .models import Category, Post, Tag
          
          class PostFilter(drf_filters.FilterSet):
              created_year = drf_filters.NumberFilter(
                  field_name="created_time", lookup_expr="year", help_text="根據(jù)文章發(fā)表年份過(guò)濾文章列表"
              )
              created_month = drf_filters.NumberFilter(
                  field_name="created_time", lookup_expr="month", help_text="根據(jù)文章發(fā)表月份過(guò)濾文章列表"
              )
              category = drf_filters.ModelChoiceFilter(
                  queryset=Category.objects.all(),
                  help_text="根據(jù)分類過(guò)濾文章列表",
              )
              tags = drf_filters.ModelMultipleChoiceFilter(
                  queryset=Tag.objects.all(),
                  help_text="根據(jù)標(biāo)簽過(guò)濾文章列表",
              )
          
              class Meta:
                  model = Post
                  fields = ["category", "tags", "created_year", "created_month"]
          

          接著我們來(lái)看 GET /posts/archive/dates/ 和 GET /posts/{id}/comments/ 這兩個(gè)接口。前者文檔中顯示了一些錯(cuò)誤的參數(shù),后者本應(yīng)該有分頁(yè)參數(shù),但是文檔卻沒(méi)有列出。

          先來(lái)看 GET /posts/archive/dates/,它對(duì)應(yīng)的 action 是 list_archive_dates,由于 action 默認(rèn)會(huì)從它所在的視圖集中繼承一些屬性,而 drf-yasg 會(huì)從這些屬性去解析接口支持的參數(shù),例如視圖集設(shè)置了 filterset_class=PostFilter 和 pagination_class=PageNumberPagination(雖然不在視圖集中顯示定義,但在全局進(jìn)行了配置),在解析 list_archive_dates 的參數(shù)時(shí),drf-yasg 錯(cuò)誤地解析到了從視圖集繼承來(lái)的 PostFilter 和 PageNumberPagination,所以就把這兩個(gè)類中定義的參數(shù)也包含進(jìn)文檔了。

          知道了原因,解決方法也就有了,在 list_archive_dates action 中把這兩個(gè)屬性設(shè)為 None,覆蓋掉視圖集中的默認(rèn)設(shè)置:

          # filename="blog/views.py"
          class PostViewSet(
              mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
          ):
            @action(
                  # ...
                  filter_backends=None, # 將 filter_backends 設(shè)為 None,filterset_class 也就不起作用了。
                  pagination_class=None,
              )
              def list_archive_dates(self, request, *args, **kwargs):
                  # ...
          

          再來(lái)看看這個(gè)接口,就沒(méi)有那些錯(cuò)誤的參數(shù)了。

          接著處理 GET /posts/{id}/comments/ 接口,我們需要文檔列出分頁(yè)參數(shù)。這個(gè)接口對(duì)應(yīng)的 action 是 list_comment。從上面的分析來(lái)看,這個(gè) action 明明已經(jīng)指定了 pagination_class=LimitOffsetPagination,為什么 drf-yasg 無(wú)法自動(dòng)檢測(cè)到分頁(yè)參數(shù)呢?原因是這個(gè) action 設(shè)置了 detail=True。當(dāng) detial=True 時(shí),drf-yasg 會(huì)將這個(gè) action 對(duì)應(yīng)的接口看做獲取單個(gè)資源的接口,因此它認(rèn)為分頁(yè)是不需要的。但實(shí)際上我們對(duì)這個(gè)接口進(jìn)行了定制,它返回的其實(shí)是評(píng)論列表。解決辦法是應(yīng)該告訴 drf-yasg,這個(gè)接口返回的是列表結(jié)果,請(qǐng)去解析列表接口相關(guān)的一些參數(shù):

          # filename="blog/views.py"
          class PostViewSet(
              mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
          ):
              @action(
                  methods=["GET"],
                  detail=True,
                  # ...
                  suffix="List",  # 將這個(gè) action 返回的結(jié)果標(biāo)記為列表,否則 drf-yasg 會(huì)根據(jù) detail=True 誤判為這是返回單個(gè)資源的接口
                  pagination_class=LimitOffsetPagination,
                  serializer_class=CommentSerializer,
              )
              def list_comments(self, request, *args, **kwargs):
                  # ...
          

          但是 drf-yasg 還是不夠聰明,當(dāng)它去解析列表接口可能的參數(shù)時(shí),順便又把 PostFilter 中的字段也一并解析了,這是用來(lái)過(guò)濾博客文章的,顯然不能用于過(guò)濾評(píng)論列表,我們需要將這些無(wú)關(guān)參數(shù)移除,解決方法在處理 GET /posts/archive/dates/ 接口時(shí)就講過(guò)了,把 filter_backends 設(shè)置成 None 就可以了。

          更正錯(cuò)誤的響應(yīng)參數(shù)

          仔細(xì)看生成的接口文檔,發(fā)現(xiàn)有 2 個(gè)接口的返回內(nèi)容是錯(cuò)誤的。

          一是 GET /posts/{id}/comments/,最初我們發(fā)現(xiàn)這個(gè)接口文檔的響應(yīng)是一個(gè)單一的評(píng)論對(duì)象,原因我們上面也分析了,drf-yasg 根據(jù) detail=True 誤地將其作為返回單一資源的接口處理了。隨著為其添加更多信息,告訴 drf-yasg 這是一個(gè)返回資源列表的接口,問(wèn)題也就順便解決了。

          二是 GET /posts/archive/dates/,這個(gè)接口的返回內(nèi)容應(yīng)該是一個(gè)日期列表,但是文檔中顯示的竟然是博客文章列表。drf-yasg 推斷的響應(yīng)類型是正確的,但內(nèi)容不對(duì)。原因也很明顯,這個(gè)接口對(duì)應(yīng)的 action 是 list_archive_dates,drf-yasg 在這個(gè) action 中沒(méi)有找到解析響應(yīng)結(jié)果的序列化器(Serializer),所以它跑去視圖集 PostViewSet 中去找了,結(jié)果找到了 PostListSerializer,然后把這個(gè)當(dāng)成了接口返回的內(nèi)容進(jìn)行解析了。

          由于這個(gè)接口返回的僅僅是一個(gè)簡(jiǎn)單的日期列表,并不涉及到序列化器,因此這里我們不使用指定 serializer_class 屬性值的方式,而是使用 swagger_auto_schema 裝飾器,直接告訴 drf-yasg 接口返回的響應(yīng):

          # filename="blog/views.py"
          class PostViewSet(
              mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
          ):
            @swagger_auto_schema(responses={200: "歸檔日期列表,時(shí)間倒序排列。例如:['2020-08', '2020-06']"})
              @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 參數(shù)的值是一個(gè)字典,字典的鍵是 HTTP 響應(yīng)碼,值可以是一個(gè)序列化器,這樣 drf-yasg 會(huì)拿這個(gè)序列化器去解析接口響應(yīng)的參數(shù);也可以是一個(gè)字符串,drf-yasg 會(huì)把字符串直接當(dāng)做接口響應(yīng)結(jié)果寫入文檔中??纯葱薷暮蟮男Ч?/p>

          至此,我們就有了一套比較完善的博客接口文檔了,而且大部分內(nèi)容均由 drf-yasg 為我們自動(dòng)生成,省去了不少手寫文檔的麻煩。

          參考資料

          以下是教程中用到的一些參考:

          • OpenAPI Specification[6]
          • drf-yasg 源碼倉(cāng)庫(kù)[7]
          • drf-yasg 官方文檔[8]

          小貼士:

          drf-yasg 的官方文檔對(duì)于這個(gè)庫(kù)的使用方法寫的不是很清晰,這篇文章中列出的一些用法都是從源碼中看出來(lái)的。如果你在使用過(guò)程中遇到了問(wèn)題,首先嘗試分析問(wèn)題的原因,然后順藤摸瓜去找到相關(guān)的源碼,看看庫(kù)的內(nèi)部是如何處理你所遇到的問(wèn)題的,這樣就可以針對(duì)性地給出解決方案了,這篇教程中列出的很多問(wèn)題以及最后給出的解決方案,都是使用的這種方式。

          體效果

          <h1></h1> 標(biāo)題字(最大)

          <h6></h6> 標(biāo)題字(最小)

          <h1 align="center"></h1>

          <strong></strong> 粗體字(突出強(qiáng)調(diào))

          <b></b> 粗體字(bold:粗體)

          <i></i> 斜體字(italic:斜體)

          <u></u> 底線,文本添加下劃線:(underline:下劃線)

          <strike></strike>或<s></s> 橫線,相當(dāng)于加刪除線文本 <del></del> HTML5

          等寬文字標(biāo)簽:對(duì)于等寬文字設(shè)置多數(shù)情況用在英文文字顯示中

          <tt></tt> 打字體,類似打字機(jī)或者等寬的文本效果。

          <code></code> 等寬文字設(shè)置內(nèi)容(定義計(jì)算機(jī)代碼文本)

          <samp></samp> 等寬文字設(shè)置內(nèi)容(定義樣本文本)

          <kbd> 定義鍵盤文本。

          <sup></sup> 文字上標(biāo)字體標(biāo)簽(super)

          <sub></sub> 文字下標(biāo)字體標(biāo)簽(subscipt)

          <address></address> 設(shè)置地址文字(可定義一個(gè)地址,比如電子郵件地址。您應(yīng)當(dāng)使用它來(lái)定義地址、簽名或者文檔的作者身份。)

          <font></font> 編輯網(wǎng)頁(yè)文字樣式

          <font face="" size="" color=""></font>

          face屬性可以用于設(shè)置文字的名稱,可以是宋體、隸書、楷體等;

          size屬性用于設(shè)置字號(hào)的大小(單位:字號(hào)),從 1 到 7 的數(shù)字,或h1-h6。瀏覽器默認(rèn)值是3。

          color用于設(shè)置字體的顏色

          <font size="3" color="red">This is some text!</font>
          <font size="2" color="blue">This is some text!</font>
          <font face="verdana" color="green">This is some text!</font>

          手冊(cè)上沒(méi)有

          <ruby></ruby>和<rt></rt> 設(shè)置文字標(biāo)注標(biāo)記

          實(shí)例:

          <ruby>當(dāng)代最可愛(ài)的人<rt>志愿軍</rt></ruby>

          立和使用列表

          定義列表

          <dl></dl>列表標(biāo)簽定義列表;
          <dt>定義列表標(biāo)題;
          <dd>定義列表內(nèi)容;

          說(shuō)明:

          1. dt和dd對(duì)應(yīng)著的, 一個(gè)dt可以對(duì)應(yīng)著多個(gè)dd;

          2. dd完全是為了dt服務(wù)的, 對(duì)標(biāo)題進(jìn)行描述;

          實(shí)例:

          <dl>
          <dt>標(biāo)題1</dt><dd>內(nèi)容11</dd><dd>內(nèi)容12</dd>
          <dt>標(biāo)題2</dt><dd>內(nèi)容21</dd><dd>內(nèi)容22</dd>
          </dl>


          有序列表(unordered list)

          <ol></ol> 列表標(biāo)簽定義一個(gè)標(biāo)有數(shù)字的列表;

          <ol type="value"></ol>

          1 默認(rèn)值。數(shù)字有序列表。(1、2、3、4)

          a 按字母順序排列的有序列表,小寫。(a、b、c、d)

          A 按字母順序排列的有序列表,大寫。(A、B、C、D)

          i 羅馬字母,小寫。(i, ii, iii, iv)

          I 羅馬字母,大寫。(I, II, III, IV)

          <ol>
          <li>聯(lián)系人:</li>xxx
          <li>聯(lián)系地址:</li>北京市豐臺(tái)區(qū)
          <li>郵政編碼:</li>100036
          </ol>


          無(wú)序列表(ordered list)

          <ul></ul> 列表標(biāo)簽定義一個(gè)標(biāo)有圓點(diǎn)的列表;

          <ul type="value"></ul>

          disc 默認(rèn)值,實(shí)心圓。

          circle 空心圓。

          square 實(shí)心方塊。

          <ul>
          <li></li>
          <li></li>
          <li></li>
          </ul>


          目錄列表 所有主流瀏覽器都支持 <dir> 標(biāo)簽。。

          <dir></dir>標(biāo)簽定義目錄列表。

          <dir>
          <li>HTML</li>
          <li>XHTML</li>
          <li>CSS</li>
          </dir>

          菜單列表 目前所有主流瀏覽器都不支持 <menu> 標(biāo)簽。

          <menu></menu>標(biāo)簽可定義一個(gè)菜單列表。

          <menu>
          <li>html</li>
          <li>xhtml</li>
          </menu>

          在實(shí)際工作中, 它的用途較少, 大部分我們還是用ul;

          另外還可以使用:

          <div align=""></div>分區(qū)標(biāo)簽,用來(lái)排版大塊HTML段落,也用于格式化表


          主站蜘蛛池模板: 国模精品视频一区二区三区| 中文字幕日韩丝袜一区| 丰满人妻一区二区三区免费视频| 国产一在线精品一区在线观看| 亚洲日本va午夜中文字幕一区| 一区二区三区影院| 国产高清一区二区三区视频| 精品无码一区二区三区在线| 免费一区二区无码东京热| 乱人伦一区二区三区| 国模无码视频一区| 亚洲一区欧洲一区| 亚洲性无码一区二区三区| 亚洲电影国产一区| 无码一区二区三区视频| 亚洲乱色熟女一区二区三区丝袜| av无码一区二区三区| 亚洲一区二区三区在线播放| 无码AⅤ精品一区二区三区| 无码8090精品久久一区| 日韩有码一区二区| 国产精品99无码一区二区| 国产主播一区二区三区| 日亚毛片免费乱码不卡一区| 高清一区高清二区视频| 日本中文一区二区三区亚洲| 杨幂AV污网站在线一区二区| 538国产精品一区二区在线| 黄桃AV无码免费一区二区三区| 亚洲线精品一区二区三区| 亚洲国产一区国产亚洲| 亚洲人成人一区二区三区| 成人区精品人妻一区二区不卡| 精品一区二区久久| 国产精品视频一区二区三区经| 中文字幕av一区| 波多野结衣一区二区免费视频| 中文字幕在线播放一区| 亚洲AV福利天堂一区二区三| 日韩精品一区二区三区老鸭窝| 午夜视频一区二区三区|