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 < 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引數就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。