Django REST Swagger实现指定api参数
作者:Z_J_Q_
为什么要指定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参数就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。