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 相关文章推荐
python中列表元素连接方法join用法实例
Apr 07 Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
Feb 08 Python
python利用微信公众号实现报警功能
Jun 10 Python
python中多个装饰器的执行顺序详解
Oct 08 Python
Python使用pyserial进行串口通信的实例
Jul 02 Python
Python scrapy增量爬取实例及实现过程解析
Dec 24 Python
Ubuntu16.04安装python3.6.5步骤详解
Jan 10 Python
Python获取、格式化当前时间日期的方法
Feb 10 Python
python中Ansible模块的Playbook的具体使用
May 28 Python
解决Keras使用GPU资源耗尽的问题
Jun 22 Python
Python对excel的基本操作方法
Feb 18 Python
Python使用Web框架Flask开发项目
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
php 破解防盗链图片函数
2008/12/09 PHP
phpQuery让php处理html代码像jQuery一样方便
2015/01/06 PHP
PHP 实现类似js中alert() 提示框
2015/03/18 PHP
php格式化电话号码的方法
2015/04/24 PHP
php实现计算百度地图坐标之间距离的方法
2016/05/05 PHP
php获取微信openid方法总结
2019/10/10 PHP
php实现统计IP数及在线人数的示例代码
2020/07/22 PHP
用js自动判断浏览器分辨率的代码
2007/01/28 Javascript
通过jquery实现tab标签浏览效果
2007/02/20 Javascript
JavaScript String.replace函数参数实例说明
2013/06/06 Javascript
js中方法重载如何实现?以及函数的参数问题
2013/08/01 Javascript
jQuery插件jcrop+Fileapi完美实现图片上传+裁剪+预览的代码分享
2015/04/22 Javascript
JavaScript数组各种常见用法实例分析
2015/08/04 Javascript
两款JS脚本判断手机浏览器类型跳转WAP手机网站
2015/10/16 Javascript
JS求Number类型数组中最大元素方法
2018/04/08 Javascript
解析Json字符串的三种方法日常常用
2018/05/02 Javascript
详解javascript中的变量提升和函数提升
2018/05/24 Javascript
vue3.0 CLI - 1 - npm 安装与初始化的入门教程
2018/09/14 Javascript
vue路由拦截器和请求拦截器知识点总结
2019/11/08 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
[01:08]DOTA2次级职业联赛 - Shield战队宣传片
2014/12/01 DOTA
浅析python 中__name__ = '__main__' 的作用
2014/07/05 Python
Pandas 数据处理,数据清洗详解
2018/07/10 Python
python使用PIL实现多张图片垂直合并
2019/01/15 Python
python 格式化输出百分号的方法
2019/01/20 Python
师范生实习个人的自我评价
2013/09/28 职场文书
体育专业个人求职信范文
2013/12/27 职场文书
单位办理社保介绍信
2014/01/10 职场文书
大学生职业规划书的范本
2014/02/18 职场文书
教师远程培训感言
2014/03/06 职场文书
村干部四风问题整改措施
2014/09/30 职场文书
罗马假日观后感
2015/06/08 职场文书
2016年小学教师政治学习心得体会
2016/01/23 职场文书
iPhone13 Pro外观确定,升级4800万镜头,4月20日发新品
2021/04/15 数码科技
Python使用random模块实现掷骰子游戏的示例代码
2021/04/29 Python
js前端面试常见浏览器缓存强缓存及协商缓存实例
2022/06/21 Javascript