Django REST Swagger实现指定api参数


Posted in Python onJuly 07, 2020

为什么要指定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参数就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Django中对数据查询结果进行排序的方法
Jul 17 Python
Python配置mysql的教程(推荐)
Oct 13 Python
Django异步任务之Celery的基本使用
Mar 23 Python
python文档字符串(函数使用说明)使用详解
Jul 30 Python
pytorch 自定义数据集加载方法
Aug 18 Python
django2.2安装错误最全的解决方案(小结)
Sep 24 Python
pyinstaller打包单文件时--uac-admin选项不起作用怎么办
Apr 15 Python
Python with语句用法原理详解
Jul 03 Python
简述 Python 的类和对象
Aug 21 Python
Pycharm新手使用教程(图文详解)
Sep 17 Python
用Python远程登陆服务器的步骤
Apr 16 Python
python plt.plot bar 如何设置绘图尺寸大小
Jun 01 Python
python中查看.db文件中表格的名字及表格中的字段操作
Jul 07 #Python
python db类用法说明
Jul 07 #Python
python文件编写好后如何实践
Jul 07 #Python
python 删除excel表格重复行,数据预处理操作
Jul 06 #Python
pandas.DataFrame.drop_duplicates 用法介绍
Jul 06 #Python
TensorFlow Autodiff自动微分详解
Jul 06 #Python
Keras loss函数剖析
Jul 06 #Python
You might like
JQuery打造PHP的AJAX表单提交实例
2009/11/03 Javascript
jQuery的选择器中的通配符使用介绍
2014/03/20 Javascript
jquery查找父元素、子元素(个人经验总结)
2014/04/09 Javascript
jQuery 浮动导航菜单适合购物商品类型的网站
2014/09/09 Javascript
jquery实现弹出层登录和全屏层注册特效
2015/08/28 Javascript
jQuery Html控件基本操作(日常收集整理)
2016/03/11 Javascript
jQuery基于ID调用指定iframe页面内的方法
2016/07/06 Javascript
vue.js默认路由不加载linkActiveClass问题的解决方法
2017/12/11 Javascript
基于vue-video-player自定义播放器的方法
2018/03/21 Javascript
vue 设置路由的登录权限的方法
2018/07/03 Javascript
解决vue-router在同一个路由下切换,取不到变化的路由参数问题
2018/09/01 Javascript
自己动手封装一个React Native多级联动
2018/09/19 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
[02:01]2018完美盛典-开场舞《双子星》
2018/12/16 DOTA
python简单判断序列是否为空的方法
2015/06/30 Python
用python制作游戏外挂
2018/01/04 Python
python实现学生管理系统
2018/01/11 Python
Django unittest 设置跳过某些case的方法
2018/12/26 Python
numpy:找到指定元素的索引示例
2019/11/26 Python
使用Bazel编译TensorBoard教程
2020/02/15 Python
浅析python 定时拆分备份 nginx 日志的方法
2020/04/27 Python
Python压缩模块zipfile实现原理及用法解析
2020/08/14 Python
Python Tkinter实例——模拟掷骰子
2020/10/24 Python
Tiqets英国:智能手机上的文化和娱乐门票
2019/07/10 全球购物
俄罗斯设计师家具购物网站:The Furnish
2019/12/01 全球购物
linux面试相关问题
2013/04/28 面试题
大专毕业生自我评价分享
2013/11/10 职场文书
应用化学专业职业生涯规划书
2013/12/31 职场文书
银行简历自我评价
2014/02/11 职场文书
服务行业口号
2014/06/11 职场文书
环卫处个人工作总结
2015/03/04 职场文书
海上钢琴师的观后感
2015/06/11 职场文书
幼儿园毕业典礼园长致辞
2015/07/29 职场文书
签约仪式致辞
2015/07/30 职场文书
室外天线与收音机天线杆接合方法
2022/04/05 无线电
Python Matplotlib绘制两个Y轴图像
2022/04/13 Python