首页 > 其他分享 >django配置swagger自动生成接口文档以及自定义参数设置

django配置swagger自动生成接口文档以及自定义参数设置

时间:2023-08-25 16:34:40浏览次数:42  
标签:自定义 get res req openapi django TYPE 参数设置 cls

  首先安装swagger所用的包

pip install drf-yasg

  

  然后再settings.py 中注册app

  

        

   

  接口采用的token认证,在settings.py配置认证方式

    

SWAGGER_SETTINGS = {
    'USE_SESSION_AUTH': False,
    'SECURITY_DEFINITIONS': {
        '身份验证': {
            'type': 'apiKey',
            'in': 'header',
            'name': 'Authorization'
        }
    },
}

  

  配好后打开的认证是这样的

  

   

  在urls.py中配置路由

    

from django.contrib import admin
from django.urls import path, include

# 使用 drf_yasg API文档生成器 视图和openapi
from django.views.static import serve
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

# 导入权限控制模块
from rest_framework import permissions

# 文档视图
schema_view = get_schema_view(
    # API 信息
    openapi.Info(
        title='接口文档',   # API文档标题
        default_version='V1',   # 版本信息
        description='接口文档',    # 描述内容
        # terms_of_service='https://qaq.com',    # 开发团队地址
        # contact=openapi.Contact(email='https://[email protected]',url='https://qaq.com'),   # 联系人信息:邮件、网址
        # license=openapi.License(name='qaq License'),    # 证书
    ),
    public=True,    # 是否公开
    # permission_classes=(permissions.AllowAny,)   # 设置用户权限

)

urlpatterns = [
    path('admin/', admin.site.urls),

    path('userManage/', include('userManage.urls')),
    path('ani/', include('ani.urls')),

    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),   # 互动模式
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),   # 文档模式
]

  

  配置好以后打开  http://127.0.0.1:8000/swagger/即可访问到接口文档页面

  

  打开查看后发现,请求的参数缺少了,返回的参数和接口实际返回的参数不一样,因为我的视图继承APIView做了一些自定义的请求参数和返回参数。

  所以需要自定义swagger

 

  util.py文件,因为自动生成的采用序列化 query_serializer参数就会将一些外键的source字段也加到参数里面,所以重新去获取序列器的字段。再定义一个

  固定格式的基类

  

from rest_framework import serializers
from drf_yasg import openapi
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.fields import ChoiceField


def serializer_to_swagger(ser_model, get_req=False):
    '''
    将序列化字段转成openapi的形式
    '''
    if ser_model is None and get_req is True:
        return {}, []
    elif ser_model is None and get_req is False:
        return {}
    dit = {}
    serializer_field_mapping = {
        ChoiceField: openapi.TYPE_INTEGER,
        PrimaryKeyRelatedField: openapi.TYPE_INTEGER,
        serializers.IntegerField: openapi.TYPE_INTEGER,
        serializers.BooleanField: openapi.TYPE_BOOLEAN,
        serializers.CharField: openapi.TYPE_STRING,
        serializers.DateField: openapi.TYPE_STRING,
        serializers.DateTimeField: openapi.TYPE_STRING,
        serializers.DecimalField: openapi.TYPE_NUMBER,
        serializers.DurationField: openapi.TYPE_STRING,
        serializers.EmailField: openapi.TYPE_STRING,
        serializers.ModelField: openapi.TYPE_OBJECT,
        serializers.FileField: openapi.TYPE_STRING,
        serializers.FloatField: openapi.TYPE_NUMBER,
        serializers.ImageField: openapi.TYPE_STRING,
        serializers.SlugField: openapi.TYPE_STRING,
        serializers.TimeField: openapi.TYPE_STRING,
        serializers.URLField: openapi.TYPE_STRING,
        serializers.UUIDField: openapi.TYPE_STRING,
        serializers.IPAddressField: openapi.TYPE_STRING,
        serializers.FilePathField: openapi.TYPE_STRING,
    }
    fields = ser_model().get_fields()
    if get_req:
        required = []
        for k, v in fields.items():
            description = getattr(v, 'label', '')
            if isinstance(v, serializers.SerializerMethodField) or getattr(v, 'source'):
                continue
            elif isinstance(v, ChoiceField):
                description += str(dict(getattr(v, 'choices', {})))
            if getattr(v, 'required', True) is not False:
                required.append(k)
            typ = serializer_field_mapping.get(type(v), openapi.TYPE_STRING)
            dit[k] = openapi.Schema(description=description, type=typ)
        return dit, required
    else:
        for k, v in fields.items():
            description = getattr(v, 'label', '')
            if isinstance(v, ChoiceField):
                description += str(dict(getattr(v, 'choices', {})))
            elif isinstance(v, serializers.SerializerMethodField):
                continue
            typ = serializer_field_mapping.get(type(v), openapi.TYPE_STRING)
            dit[k] = openapi.Schema(description=description, type=typ)

        return dit


class ViewSwagger(object):
    """
    openapi视图类
    重写请求参数和返回参数,调用对应的类方法即可
    """

    get_operation = '获取数据'
    get_req_params = []
    get_req_body = None
    get_res_data = None
    get_res_examples = {'json': {}}
    get_res_description = ' '
    get_res_code = 200

    post_operation = '新增数据'
    post_req_params = []
    post_req_body = None
    post_res_data = None
    post_res_examples = {'json': {}}
    post_res_description = ' '
    post_res_code = 200

    put_operation = '修改数据'
    put_req_params = []
    put_req_body = None
    put_res_data = None
    put_res_examples = {'json': {}}
    put_res_description = ' '
    put_res_code = 200

    delete_operation = '删除数据'
    delete_req_params = []
    delete_req_body = None
    delete_res_data = None
    delete_res_examples = {'json': {}}
    delete_res_description = ' '
    delete_res_code = 200

    @classmethod
    def req_serialize_schema(cls, serializer):
        return serializer_to_swagger(serializer, get_req=True)

    @classmethod
    def res_serialize_schema(cls, serializer):
        return serializer_to_swagger(serializer, get_req=False)

    @classmethod
    def get(cls):
        ret = {
            'manual_parameters': cls.get_req_params,
            'request_body': cls.get_req_body,
            'operation_summary': cls.get_operation,
            'responses': {
                cls.get_res_code: openapi.Response(description=cls.get_res_description, schema=cls.get_res_data,
                                                   examples=cls.get_res_examples)}
        }
        return ret

    @classmethod
    def post(cls):
        ret = {
            'manual_parameters': cls.post_req_params,
            'request_body': cls.post_req_body,
            'operation_summary': cls.post_operation,
            'responses': {
                cls.post_res_code: openapi.Response(description=cls.post_res_description, schema=cls.post_res_data,
                                                    examples=cls.post_res_examples)}
        }
        return ret

    @classmethod
    def put(cls):
        ret = {
            'manual_parameters': cls.put_req_params,
            'request_body': cls.put_req_body,
            'operation_summary': cls.put_operation,
            'responses': {
                cls.put_res_code: openapi.Response(description=cls.put_res_description, schema=cls.put_res_data,
                                                   examples=cls.put_res_examples)}
        }
        return ret

    @classmethod
    def delete(cls):
        ret = {
            'manual_parameters': cls.delete_req_params,
            'request_body': cls.delete_req_body,
            'operation_summary': cls.delete_operation,
            'responses': {
                cls.delete_res_code: openapi.Response(description=cls.delete_res_description,
                                                      schema=cls.delete_res_data,
                                                      examples=cls.delete_res_examples)}
        }
        return ret

 

  下面只要在视图中单独定义对应的字段即可,gender.py 如下

  

import copy

from django.utils.decorators import method_decorator

from ani import models
from ani.serializer import GenderSerializer
from utils.decorators import request_decrypt, auth_token
from utils.myView import MyPagination, MyView, MixinGetList, MixinPostCreateModel, MixinPutUpdateModel, \
    MixinDeleteDestroyModel

from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from utils.util import ViewSwagger


class APISwagger(ViewSwagger):
    serializer = GenderSerializer
    res_ser_schema = ViewSwagger.res_serialize_schema(serializer)
    req_ser_schema, req_ser_required_fields = ViewSwagger.req_serialize_schema(serializer)
    get_operation = '获取数据'
    get_req_params = [
        openapi.Parameter(name='name__icontains', in_=openapi.IN_QUERY, description='过滤包含该字段', type=openapi.TYPE_STRING,
                          required=False),
    ]
    get_req_body = None
    get_res_data = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
            'data': openapi.Schema(description='', type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_OBJECT, properties={
                **res_ser_schema
            })),
            'total': openapi.Schema(description='总数', type=openapi.TYPE_INTEGER),
        })
    get_res_examples = {'json': {}}
    get_res_description = 'get返回'
    get_res_code = 200

    post_schema = copy.copy(req_ser_schema)
    del post_schema['id']
    post_operation = '新增数据'
    post_req_params = []
    post_req_body = openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                **post_schema
                },
            required=req_ser_required_fields
        )
    post_res_data = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
                **res_ser_schema
        })
    post_res_examples = {'json': {}}
    post_res_description = ' '
    post_res_code = 200

    put_fields = req_ser_required_fields
    put_fields.append('id')
    put_operation = '新增数据'
    put_req_params = []
    put_req_body = openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            **req_ser_schema
        },
        required=put_fields
    )
    put_res_data = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        **res_ser_schema
    })
    put_res_examples = {'json': {}}
    put_res_description = ' '
    put_res_code = 200


@method_decorator([swagger_auto_schema(**APISwagger.delete())], name='delete')
@method_decorator([swagger_auto_schema(**APISwagger.put())], name='put')
@method_decorator([swagger_auto_schema(**APISwagger.post())], name='post')
@method_decorator([swagger_auto_schema(**APISwagger.get())], name='get')
# @method_decorator(auth_token, name='get')
class GenderView(MyView, MixinGetList, MixinPostCreateModel, MixinPutUpdateModel, MixinDeleteDestroyModel):
    """
    get:
        查询
    post:
        新增
    put:
        修改
    delete:
        删除

    """
    queryset = models.Gender.objects.all()
    serializer_class = GenderSerializer
    all_serializer_class = GenderSerializer
    filter_class = ['name__icontains']
    pagination_class = MyPagination
    lookup_field = 'id'
    ordeing_field = ('-id',)

  

  打开的接口文档变成

  

 

  try it out 调用接口,得到一样的数据

  

   

  注意:如果是post请求提交表单数据的时候,那么这个视图只能解析  parser_classes = [MultiPartParser],自定义的字段和get请求差不多,只需要将 _in=openapi.IN_FORM  即可

 

  项目文件结构

  

    

 

 

 

  

标签:自定义,get,res,req,openapi,django,TYPE,参数设置,cls
From: https://www.cnblogs.com/moon3496694/p/17657283.html

相关文章

  • 黑魂237 自定义导演模块导轨的功能实现
    打开脚本playablebehaviour。 这个代码能够开启自定义导轨的播放启动功能。当导演模式开始了,所有的自定义导轨会被启动。 这个代码是指到结束才触发。 这个代码是时间轴到自定义导轨上会触发。 这个代码是时间轴不在自定义导轨上会触发。 ......
  • ios开发之 -- xib关联自定义view
    在xib下使用自定义的view,因为很多时候,可能幸亏自顶一个view,然后在view里面填充控件,但是需要重写很多无用的代码,而且很容易出错不说,还很好工作量,使用xib的话,分钟搞定一个view,话不多说,步骤如下:1,先创建一个view2,创建一个xib3,"File'sOwner"的class继承为:MyView(即自定义创建的视图......
  • 创建第一个Django app-part5
    自动化测试开始第一个测试首先有一个bugpython3manage.pyshell创建一个测试来暴露这个bug将下面的代码写入polls应用里的tests.py文件内点击查看代码fromdjango.testimportTestCase#Createyourtestshere.importdatetimefromdjango.utilsimporttim......
  • Hue时间参数设置
    Oozie常用的系统常量常量使用公式含义说明${coord:minutes(intn)}返回日期时间:从一开始,周期执行n分钟${coord:hours(intn)}返回日期时间:从一开始,周期执行n*60分钟${coord:days(intn)}返回日期时间:从一开始,周期执行n*24*60分钟${coord:months(intn......
  • 【Angular】如何将自定义组件绑定为FormControl?
    参考资料:简单Demo:AngularFormcontrolenameCustomComponent关键实现说明:ControlValueAccessor:CustomFormComponentsinAngularAngular自定义表单控件(中文)关于muti:true的说明......
  • python独立脚本应用Django项目的环境
    一、需求说明一直用Django在开发一个网站项目,其中的注册用户和登录,都是使用Django自带的认证系统。主要是对密码的加密,在注册或者登录的时候,前端传递多来的密码,我会使用Django的set_password()方法在加密一次经过加密后的数据库中的数据样子如下:......
  • 0x00 BabyDjango,启动
    0x00BabyDjango,启动新建项目此处我使用之前的解释器(主要是不想再从0到×再安装一些包,难受...)原先解释器中得先装好Django第三方库新建项目初始目录如下启动在终端中,指定地址和端口进行运行pythonmanage.pyrunserverip:portDjango项目结构说明一个常规目录......
  • element-ui中表格@row-click方法自定义传参的写法
     @row-click="(row,column,e)=>handleRowClicked(row,column,e,'unitName')"参考:https://blog.csdn.net/weixin_46060121/article/details/120151005   ......
  • Python Web:Django、Flask和FastAPI框架对比
    Django、Flask和FastAPI是PythonWeb框架中的三个主要代表。这些框架都有着各自的优点和缺点,适合不同类型和规模的应用程序。Django:Django是一个全功能的Web框架,它提供了很多内置的应用程序和工具,使得开发Web应用程序更加容易。Django采用了MTV(模型-模板-视图)设计模式,提供ORM......
  • 在博客园中美化博客,并使用自定义的主题
    一、开通博客园JS权限这部分不再赘述,可以点击下方链接,查看如何申请博客园JS权限申请二、在博客园中设置相关内容打开你的博客首页->管理->设置设置博客皮肤为“Custom”勾选禁用默认CSS样式三、在博客园设置中粘贴相应代码此部分代码粘贴到【页面定制......