django-rest-framework 自定義swagger

前言

之前的文章編寫了一個返回json的例子,直接用瀏覽器進行get請求雖然成功了, 但是接口文檔的樣式很難看, 不好用. 而且提示沒有訪問權限.

我們一般都希望能夠直接在接口文檔中進行請求, 以測試接口, 本篇文章中會給出一個自定義swagger(openapi)的例子. 使接口文檔變得美觀可用, 可以填寫參數, 可以進行請求以觀察數據格式, 測試接口是否可用.

環境

workon python35
pip list
chardet (3.0.4)
coreapi (2.3.3)
coreschema (0.0.4)
Django (1.11.6)
django-rest-swagger (2.1.2)
django-simple-serializer (2.0.7)
djangorestframework (3.7.1)
future (0.16.0)
idna (2.6)
itypes (1.1.0)
Jinja2 (2.9.6)
MarkupSafe (1.0)
openapi-codec (1.3.2)
pip (9.0.1)
pytz (2017.2)
requests (2.18.4)
setuptools (36.6.0)
simplejson (3.11.1)
uritemplate (3.0.0)
urllib3 (1.22)
wheel (0.30.0)

阿里云的源中 最新版的django-rest-frmework版本為3.7.1
3.6 與 3.7的結構稍有不同. 我之前用3.6, 但是以下對swagger的修改以3.7.1版本為基準. 理解原理之后不同版本只需要稍作修改即可.

第一步修改配置

進入settings.py 文件, 確保INSTALLED_APPS中包含rest_framework

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_swagger',
    'mytest',
]

我們導入了三個框架
rest_framework
rest_framework_swagger
mytest (之前的文章中編寫簡單接口的app)

然后在settings.py 文件中添加以下代碼

REST_FRAMEWORK = {
    # 下面這一行表示接口文檔的訪問權限, AllowAny不做權限限制.
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
    # 'PAGE_SIZE': 10,
    'PAGINATE_BY':10,
}


SWAGGER_SETTINGS = {
    # 基礎樣式
    'SECURITY_DEFINITIONS': {
        "basic":{
            'type': 'basic'
        }
    },
    # 如果需要登錄才能夠查看接口文檔, 登錄的鏈接使用restframework自帶的.
    'LOGIN_URL': 'rest_framework:login',
    'LOGOUT_URL': 'rest_framework:logout',
    # 'DOC_EXPANSION': None,
    # 'SHOW_REQUEST_HEADERS':True,
    # 'USE_SESSION_AUTH': True,
    # 'DOC_EXPANSION': 'list',
    # 接口文檔中方法列表以首字母升序排列
    'APIS_SORTER': 'alpha',
    # 如果支持json提交, 則接口文檔中包含json輸入框
    'JSON_EDITOR': True,
    # 方法列表字母排序
    'OPERATIONS_SORTER': 'alpha',
    'VALIDATOR_URL': None,
}

第二步編寫自定義的swagger接口文檔頁面.

思路:
之前urls.py中的接口文檔頁面來自這里

from rest_framework.schemas import get_schema_view

查看源碼, 繼承schema, 返回schema的子類即可.

接下來編寫自己的schema

from rest_framework.permissions import AllowAny
from rest_framework.schemas import SchemaGenerator
from rest_framework.schemas.generators import LinkNode, insert_into
from rest_framework.renderers import *
from rest_framework_swagger import renderers
from rest_framework.response import Response

# from rest_framework.schemas import SchemaGenerator
class MySchemaGenerator(SchemaGenerator):

    def get_links(self, request=None):
        # from rest_framework.schemas.generators import LinkNode,
        links = LinkNode()

        paths = []
        view_endpoints = []
        for path, method, callback in self.endpoints:
            view = self.create_view(callback, method, request)
            path = self.coerce_path(path, method, view)
            paths.append(path)
            view_endpoints.append((path, method, view))

        # Only generate the path prefix for paths that will be included
        if not paths:
            return None
        prefix = self.determine_path_prefix(paths)

        for path, method, view in view_endpoints:
            if not self.has_view_permissions(path, method, view):
                continue
            link = view.schema.get_link(path, method, base_url=self.url)
            # 添加下面這一行方便在views編寫過程中自定義參數.
            link._fields += self.get_core_fields(view)

            subpath = path[len(prefix):]
            keys = self.get_keys(subpath, method, view)

            # from rest_framework.schemas.generators import LinkNode, insert_into
            insert_into(links, keys, link)

        return links

    # 從類中取出我們自定義的參數, 交給swagger 以生成接口文檔.
    def get_core_fields(self, view):
        return getattr(view, 'coreapi_fields', ())


class SwaggerSchemaView(APIView):
    _ignore_model_permissions = True
    exclude_from_schema = True

    # from rest_framework.permissions import AllowAny
    permission_classes = [AllowAny]
    # from rest_framework_swagger import renderers
    # from rest_framework.renderers import *
    renderer_classes = [
        CoreJSONRenderer,
        renderers.OpenAPIRenderer,
        renderers.SwaggerUIRenderer
    ]

    def get(self, request):
        generator = MySchemaGenerator(title='xxxxx',
                                      description='''xxxxx''')

        schema = generator.get_schema(request=request)

        # from rest_framework.response import Response
        return Response(schema)

上面的代碼中我加了注釋, 寫出了需要用到的一些方法, 參數, 類 都是從哪里import進來的.
上面的代碼自定義了一個swagger頁面, 加入了自定義參數的方法, 設置了訪問權限(AllowAny), 添加了title和description,

原理, 其實就是繼承父類, 重寫方法以覆蓋父類中的方法, 修改子類中overwrite的方法以添加我們想要的內容.

上面的代碼其實寫在哪里都可以, 找得到就行,我一般寫在views.py 文件中和其他接口放在一起, 畢竟 http://xxxxx/docs/ 和/api/getjson 這樣的接口一樣都返回一個視圖.

最后一步

修改urls.py文件, 把接口放出去.

from django.conf.urls import url, include
from django.contrib import admin
from rest_framework.schemas import get_schema_view
from mytest.views import ReturnJson
import mytest
# 下面是剛才自定義的schema
from mytest.views import SwaggerSchemaView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^docs/', SwaggerSchemaView.as_view(), name='apiDocs'),
    url(r'^api/getjson', ReturnJson.as_view()),
]

注意上面我們添加了兩個接口.
api-auth/docs/
還記得配置文件中的他們嗎

'LOGIN_URL': 'rest_framework:login',
'LOGOUT_URL': 'rest_framework:logout',

api-auth/就是為他倆準備的. 因為有時我們需要讓接口文檔登錄之后才能夠被看到..

最后運行項目看到

swagger0.png

剩下的問題

我們的第一個接口沒有參數. 向接口文檔的getjson接口添加一個參數.

修改 getjson接口對應的views.py文件中的類.ReturnJson類.
添加以下代碼

def DocParam(name="default", location="query",
             required=True, description=None, type="string",
             *args, **kwargs):
    return coreapi.Field(name=name, location=location,
                         required=required, description=description,
                         type=type)


class ReturnJson(APIView):

    coreapi_fields=(
        DocParam("token"),
    )

    def get(self, request, *args, **kwargs):
        return JsonResponse("Hello world!!!!!!!!++++++中文測試")

這是所有的import

from django.shortcuts import render
from rest_framework.views import APIView
from dss.Serializer import serializer
from django.http import HttpResponse, HttpRequest
from rest_framework.permissions import AllowAny
from rest_framework.schemas import SchemaGenerator
from rest_framework.schemas.generators import LinkNode, insert_into
from rest_framework.renderers import *
from rest_framework_swagger import renderers
from rest_framework.response import Response
# from rest_framework.schemas import *

我也忘了. coreapi.Field是從哪里import的了....
以上代碼為 getjson接口添加了token參數.

最終效果.

token0.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容