1. 程式人生 > 程式設計 >Django REST Swagger實現指定api引數

Django REST Swagger實現指定api引數

為什麼要指定swagger的api引數

api的引數有多種型別:

query 引數,如 /users?role=admin

path 引數,如 /users/{id}

header 引數,如 X-MyHeader: Value

body 引數,描述POST,PUT,PATCH請求的body

form 引數,描述 Content-Type of application/x-www-form-urlencoded 和 multipart/form-data 的請求報文body的引數

swagger指定api引數就可以在文件相應的api條目中顯示出api的描述、正常輸出、異常輸出、引數的名稱、描述、是否必填、值型別、引數型別對不同的引數型別有不同的顯示效果。swagger是可互動的api文件,可以直接填入文件顯示的引數的值併發送請求,返回的結果就會在文件中顯示。

Django REST Swagger實現指定api引數

難點

對 Django REST Swagger < 2 的版本,要指定swagger的api引數非常容易,只要將相關說明以特定格式和yaml格式寫在相應api的檢視函式的文件字串(DocStrings)裡,swagger就會自動渲染到文件中。比如這樣的格式:

def cancel(self,request,id):
 """
 desc: 取消任務,進行中的參與者得到報酬
 ret: msg
 err: 404頁面/msg
 input:
 - name: id
 desc: 任務id
 type: string
 required: true
 location: path
 """

但是在2.0版本之後,Django REST Swagger廢棄了對yaml文件字串的支援,不會渲染出任何內容。

一種解決方案

在Django REST framework基於類的api檢視中定義filter_class過濾出模型(models)的特定欄位,swagger會根據這些欄位來渲染。

from django_filters.rest_framework.filterset import FilterSet

class ProductFilter(FilterSet):

 class Meta(object):
 models = models.Product
 fields = (
  'name','category','id',)

class PurchasedProductsList(generics.ListAPIView):
 """
 Return a list of all the products that the authenticated
 user has ever purchased,with optional filtering.
 """
 model = Product
 serializer_class = ProductSerializer
 filter_class = ProductFilter

 def get_queryset(self):
 user = self.request.user
 return user.purchase_set.all()

這個解決方法只解決了一半問題,只能用在面向模型的api,只能過濾模型的一些欄位,而且api引數名與模型欄位名不一致時還要額外處理。

啟發

查閱Django REST Swagger的文件,Advanced Usage提到,基於類的文件api檢視是這樣的:

from rest_framework.response import Response
from rest_framework.schemas import SchemaGenerator
from rest_framework.views import APIView
from rest_framework_swagger import renderers

class SwaggerSchemaView(APIView):
 permission_classes = [AllowAny]
 renderer_classes = [
 renderers.OpenAPIRenderer,renderers.SwaggerUIRenderer
 ]

 def get(self,request):
 generator = SchemaGenerator()
 schema = generator.get_schema(request=request)

 return Response(schema)

說明文件是根據schema變數來渲染的,所以可以通過過載schema變數,利用yaml包解析出api檢視函式的文件字串中的引數定義賦值給schema變數。

更好的解決方法

建立schema_view.py:

from django.utils.six.moves.urllib import parse as urlparse
from rest_framework.schemas import AutoSchema
import yaml
import coreapi
from rest_framework_swagger.views import get_swagger_view

class CustomSchema(AutoSchema):
 def get_link(self,path,method,base_url):

 view = self.view
 method_name = getattr(view,'action',method.lower())
 method_docstring = getattr(view,method_name,None).__doc__
 _method_desc = ''

 fields = self.get_path_fields(path,method)

 try:
  a = method_docstring.split('---')
 except:
  fields += self.get_serializer_fields(path,method)
 else:
  yaml_doc = None
  if method_docstring:
  try:
   yaml_doc = yaml.load(a[1])
  except:
   yaml_doc = None

  # Extract schema information from yaml

  if yaml_doc and type(yaml_doc) != str:
  _desc = yaml_doc.get('desc','')
  _ret = yaml_doc.get('ret','')
  _err = yaml_doc.get('err','')
  _method_desc = _desc + '\n<br/>' + 'return: ' + _ret + '<br/>' + 'error: ' + _err
  params = yaml_doc.get('input',[])

  for i in params:
   _name = i.get('name')
   _desc = i.get('desc')
   _required = i.get('required',False)
   _type = i.get('type','string')
   _location = i.get('location','form')
   field = coreapi.Field(
   name=_name,location=_location,required=_required,description=_desc,type=_type
   )
   fields.append(field)
  else:
  _method_desc = a[0]
  fields += self.get_serializer_fields(path,method)

 fields += self.get_pagination_fields(path,method)
 fields += self.get_filter_fields(path,method)

 manual_fields = self.get_manual_fields(path,method)
 fields = self.update_fields(fields,manual_fields)

 if fields and any([field.location in ('form','body') for field in fields]):
  encoding = self.get_encoding(path,method)
 else:
  encoding = None

 if base_url and path.startswith('/'):
  path = path[1:]

 return coreapi.Link(
  url=urlparse.urljoin(base_url,path),action=method.lower(),encoding=encoding,fields=fields,description=_method_desc
 )

schema_view = get_swagger_view(title='API')

urls.py中指向schema_view:

from .schema_view import schema_view

urlpatterns = [
 url(r'^v1/api/',include([
 url(r'^doc/',schema_view),])),

然後在需要指定api引數的檢視類(如APIView或ModelViewSet)中過載schema:

schema = CustomSchema()

以上這篇Django REST Swagger實現指定api引數就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。