在djangorestframework中使用yaml格式的注释

2017-02-16  本文已影响0人  爱林林爱生活

0x01

最近在项目中要对api进行大规模重构,并且工具源码注释生成文档,比较swagger和spihx之后,觉得swagger更适合做api文档,可以在web页面中直接请求对应的api,很是方便。使用最新版的django-rest-swagger(drs)生成djangorestframework(drf)生成文档的时候,drs只会根据视图中的docstring来生成Link(swagger的单条文档记录)的描述,根据ViewSet中的serializer中定义的fields以及pagination_class定义的分页类来生成parameters,如果想要根据文档来插入一些parameters时,可以发现drs的可定制化程度很低,于是我决定做一些定制化。

0x02 代码

在制定花的过程中我主要重写了drf中的SchemaGenerator的get_description,把视图中的docstring按照yaml格式解析出来,并且返回docstring中的第一行作为description,如果视图没有docstring的话,_SchemaGenerator会按照视图名称自动生成相应的description。接下来是重写get_link方法,前面说过,一条Link是swagger页面中的一条文档记录,如果有yamlobj的话,则根据固定的格式解析yamlobj,然后解析出来的属性加到Link当中去。最后重写get_swagger_view 方法,使用新写的SchemaGenerator。

from rest_framework.schemas import SchemaGenerator as _SchemaGenerator
from rest_framework_swagger import renderers
from rest_framework.compat import coreapi, urlparse
from django.utils.encoding import smart_text
from rest_framework.utils import formatting

class SchemaGenerator(_SchemaGenerator):
    def get_description(self, path, method, view):
        method_name = getattr(view, 'action', method.lower())
        method_docstring = getattr(view, method_name, None).__doc__
        self.yamlobj = None
        if method_docstring:
            method_docstring = formatting.dedent(smart_text(method_docstring))
            self.yamlobj = yaml.load(method_docstring)
            return method_docstring.splitlines()[0]
        return super(SchemaGenerator, self).get_description(path, method, view)

    def get_link(self, path, method, view):
        """
        Return a `coreapi.Link` instance for the given endpoint.
        """
        fields = self.get_path_fields(path, method, view)
        fields += self.get_serializer_fields(path, method, view)
        fields += self.get_pagination_fields(path, method, view)
        fields += self.get_filter_fields(path, method, view)

            if fields and any([field.location in ('form', 'body') for field in fields]):
                encoding = self.get_encoding(path, method, view)
            else:
                encoding = None

            description = self.get_description(path, method, view)
            if isinstance(self.yamlobj, dict):
                def get_localtion(parameter):
                    if method == 'GET':
                        return 'query'
                    return parameter.get('paramType', 'formData')
                parameters = self.yamlobj.get('parameters', [])
                fields += [coreapi.Field(name=x['name'], location=get_localtion(x),     required=x.get('required', True, ), description=x.get('description', ''),     type=x.get('type', 'string')) for x in parameters]

            if self.url and path.startswith('/'):
                path = path[1:]

            return coreapi.Link(
                url=urlparse.urljoin(self.url, path),
                action=method.lower(),
                encoding=encoding,
                fields=fields,
                description=description
        )


def get_swagger_view(title=None, url=None, patterns=None, urlconf=None):
    """
    Returns schema view which renders Swagger/OpenAPI.
    """
    class SwaggerSchemaView(APIView):
        _ignore_model_permissions = True
        exclude_from_schema = True
        permission_classes = [AllowAny]
        renderer_classes = [
            CoreJSONRenderer,
            renderers.OpenAPIRenderer,
            renderers.SwaggerUIRenderer
        ]

        def get(self, request):
            generator = SchemaGenerator(
                title=title,
                url=url,
                patterns=patterns,
                urlconf=urlconf
            )
             schema = generator.get_schema(request=request)

            if not schema:
                raise exceptions.ValidationError(
                    'The schema generator did not return a schema Document'
                )

            return Response(schema)

    return SwaggerSchemaView.as_view()
上一篇下一篇

猜你喜欢

热点阅读