Django REST Swagger实现指定api参数
作者:Z_J_Q_ 发布时间:2023-03-10 05:48:58
为什么要指定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()
来源:https://blog.csdn.net/Z_J_Q_/article/details/94205225


猜你喜欢
- #/bin/sh #检测mysql server是否正常提供服务 mysqladmin -u sky -ppwd -h localhost
- go的各种import最简单的:package main import "fmt"func main() {  
- 前言本文的内容主要是介绍了MYSQL每隔10分钟进行分组统计的实现方法,在画用户登录、操作情况在一天内的分布图时会非常有用,之前我只知道用「
- 1、引言续上一篇《一行代码,导入Python所有库》不知道是不是都跟小鱼一样,把剩下的时间来学(撩)习(妹)。为了体现小鱼在懒上的造就,小鱼
- 近几年来,nosql大行其道,json更是火的一塌糊涂,作为数据库的元老,mysql在5.7版本中添加了对json数据的支持。这片博客主要介
- Python最近挺火呀,比鹿晗薛之谦还要火,当然是在程序员之间。下面我们看看有关Python的相关内容。上一篇文章我们已经介绍了部分Pyth
- 本文实例讲述了Python实现检测文件MD5值的方法。分享给大家供大家参考,具体如下:前面介绍过Python计算文件md5值的方法,这里分析
- Python DataFrame 如何设置列表字段/元素类型?比如笔者想将列表的两个字段由float64设置为int64,那么就要用到Dat
- 慢查询首先,无论进行何种优化,开启慢查询都算是前置条件。慢查询机制,将记录过慢的查询语句(事件),从而为DB维护人员提供优化目标。检查慢查询
- 昨天在做一道CTF题的时候碰到了一个图片异或的问题,操作大概如下:将一个图片读入,然后每字节进行异或操作,核心代码可简化为以下:#codin
- Python 是最流行、功能最强大的编程语言之一。由于它是自由开源的,因此每个人都可以使用。大多数 Fedora 系统都已安装了该语言。Py
- 最常见的方式就是为字段设置主键或唯一索引,当插入重复数据时,抛出错误,程序终止,但这会给后续处理带来麻烦,因此需要对插入语句做特殊处理,尽量
- 本文实例讲述了python面试题之列表声明。分享给大家供大家参考,具体如下:下面程序输出的结果为?val = [['a']*
- 一、innodb行锁分类 record lock:记录锁,也就是仅仅锁着单独的一行 gap lock:区间锁,仅仅锁住一个区间(注意这里的区
- 关于这篇文章有几句话想说,首先给大家道歉,之前学的时候真的觉得下述的是比较厉害的东西,但是后来发现真的是基础中的基础,内容还不是很完全。再看
- 业务背景: 基本业务场景是这样的,请求数据(车辆vin信息)进入到接口中,需要先判断其在数据库中的状态,如果库中不存在该vin,或者该vin
- 本文实例分析了Go语言中关闭带缓冲区的频道。分享给大家供大家参考。具体分析如下:Go语言提供了两种频道,带缓冲区和不带缓冲区的。不带缓冲区的
- 迭代器迭代器协议对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么返回一个异常来终止本次迭代。(只能往前走,不能往后退!)
- 定义一个banner.js文件,代码如下;window.requestAnimationFrame = window.requestAnim
- python 实现单例的方法第一种方法:使用基类New 是真正创建实例对象的方法,所以重写基类的new 方法,以此保证创建对象的时候只生成一