6.REST 高阶
一、 自定义接口规范(渲染器)
1. 渲染器的基本原理
序列化在返回数据后并不是直接做为响应数据,而是经过渲染器的渲染,生成不同格式的响应内容 。
重构渲染器就是重写父类渲染器的 render 方法 。
render(self, data, accepted_media_type=None, renderer_context=None)
data
: 响应数据(序列化器的.data 属性),等同于 renderer_context[" response "].data 的值accepted_media_type=None
: 可选的。如果提供,这是由内容协商阶段确定的所接受的媒体类型。- 根据客户端的 Accept: 头,这可能比渲染器的 media_type 属性更具体,可能包括媒体类型参数。例如 "application/json; nested=true" 。
renderer_context=None
: 可选的。如果提供,这是一个由 view 提供的上下文信息的字典。- 默认情况下这个字典会包括以下键: view , request , response , args , kwargs 。
renderer_context[" view "]
对应调用的视图函数renderer_context[" request "]
对应本次请求对象,包含所有请求数据,如请求头,请求参数等等renderer_context[" response "]
对应本次响应对象,包含所有响应数据,如响应头,状态码,响应数据
2. REST 框架 渲染器配置
在 settings.py
中添加 drf 全局配置
# settings.py
# rest框架配置
REST_FRAMEWORK = {
# 添加全局异常处理模块
'EXCEPTION_HANDLER': 'utils.exception.my_exception_handler',
# 默认的渲染器
'DEFAULT_RENDERER_CLASSES': (
# 默认的渲染器 配置
# 'rest_framework.renderers.JSONRenderer',
# 'rest_framework.renderers.BrowsableAPIRenderer',
'utils.renderers.MyRenderer',
)
}
utils.renderers.MyRenderer
对应的是你文件路径
创建 utils 目录
,然后在下面新建 renderers.py
文件 和 exception.py
文件
3. 正常信息获取
# renderers.py
# 通用返回过滤器
from rest_framework.renderers import JSONRenderer
# 继承空 返回 JSON 的渲染器
class MyRenderer(JSONRenderer):
# 重构 render 方法
def render(self, data, accepted_media_type=None, renderer_context=None):
# 默认把 data 作为响应数据
resp_content = data
if renderer_context:
status_code = renderer_context['response'].status_code # 响应状态码
if str(status_code).startswith('2'): # 以 2 开头表示 响应正常
# 判断响应内容是否为列表,如果不是则需要转换为列表形式(接口要求)
if not isinstance(resp_content, list):
resp_content = [resp_content]
res = {'msg': 'success', 'retcode': status_code, 'retlist': resp_content}
return super().render(res, accepted_media_type, renderer_context)
# 异常情况
return super().render(resp_content, accepted_media_type, renderer_context)
3. 异常信息获取
REST 默认情况可以处理的异常有
- 在 REST framework 内部产生的 APIException 的子类异常。
- 原生 Django 的 Http404 异常.
- 原生 Django 的 PermissionDenied 异常.
异常处理:
# exception.py
# REST 框架异常处理器
from rest_framework.views import exception_handler
# 处理异常返回 过滤器
def my_exception_handler(exc, context):
# 获取标准的错误响应
response = exception_handler(exc, context)
if response:
# 成功捕获到异常
response.data['msg'] = 'error' # 错误信息标记
response.data['retcode'] = response.status_code # 同步状态码
response.data['error'] = str(exc) # 采用详细的议程消息
response.data.pop('detail') # 去除 detail 消息
return response
二、 在线接口文档 --- swagger
Django REST Swagger 项目已经不维护了,并且不支持最新的 Django
drf-yasg
项目作为接口文档生成器。yasg 的功能非常强大,可以同时支持多种文档格式。
1. 配置安装
1. 安装最新版 drf-yasg
pip install -U drf-yasg
2. 注册
drf-yasg
属于 django 的插件,因此需要注册到配置文件中 settings.py
staticfiles
: 默认的静态文件。默认是已经注册了的,如果没有注册需要手动注册
INSTALLED_APPS = [
'django.contrib.staticfiles',
'drf_yasg',
]
3. 配置路由
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
# 文档视图
from rest_framework import permissions
# 定义 swagger 视图
swagger_view = get_schema_view(
openapi.Info(
title='SQPT API',
default_version='v1',
description='SQPT接口文档',
terms_of_service='https://www.pupper.cn',
contact=openapi.Contact(email='pupper.cheng@gmail.com'),
license=openapi.License(name='BSD License'),
),
public=True, # 是否公开
# 权限 class 是元组类型
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
# 互动模式
path('swagger/', swagger_view.with_ui('swagger', cache_timeout=0,)),
# 文档模式
path('redoc/', swagger_view.with_ui('redoc', cache_timeout=0,)),
]
2. 定制化用法(viewset 模式)
函数视图
: 采用swagger_auto_schema
装饰器 修饰视图函数
# views.py
from drf_yasg.utils import swagger_auto_schema
@swagger_auto_schema(method='GET',operation_summary='定制化API',operation_description='接口描述。。')
@api_view(['GET'])
def customer_api(request):
return Response(data={"retcode":status.HTTP_200_OK,'msg':'building...'})
类视图
: 采用 django 装饰器 配合 swagger 的 装饰器 来实现
# views.py
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
@method_decorator(name='list', decorator=swagger_auto_schema(operation_description="列出所有步骤数据"))
@method_decorator(name='create', decorator=swagger_auto_schema(operation_description="创建步骤"))
@method_decorator(name='update', decorator=swagger_auto_schema(operation_description="更新步骤"))
@method_decorator(name='destroy', decorator=swagger_auto_schema(operation_description="删除步骤"))
@method_decorator(name='retrieve', decorator=swagger_auto_schema(operation_description="提取单个步骤数据"))
class CaseViewSet(viewsets.ModelViewSet):
queryset = Case.objects.all()
serializer_class = CaseSerializer
三、 前端对接
前端样式地址 提取码:sqpt
配置 Django 静态文件服务, 是 开发时
使用的 一种 临时方案
,
在 autotpsite/urls.py 文件
中配置静态服务
# autotpsite/urls.py
# 静态文件服务
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('sqpt.urls')),
]+static('/', document_root='dist') # 配置静态文件访问路径
如果 http 请求的 url 不是以 api/project 开头, Django 就会认为是要访问 dist 目录下面的静态文件。
当我们访问 html 页面时,js 代码会自动请求后台数据,渲染到当前页面上,为了适配前端,减少改动工作,先将后台 URL 进行改动
# autotpsite/urls.py
urlpatterns = [
path('api/', include('sqpt.urls')),
]
四、 接口开发完善
1. 嵌套字段内容显示
{"msg":"success","retcode":200,"retlist":
[{"id":1,"file_path":"haiwen_Test.yml","config":1,"suite":null}]}
显示 config 的具体内容:指定 config 为对应的序列化器对象
# serializers.py
class ConfigSerializer(serializers.ModelSerializer):
class Meta:
model = Config
fields = '__all__'
class CaseSerializer(serializers.ModelSerializer):
# config 字段为 Config 序列化器 , REST 会自动提取其值
config = ConfigSerializer()
class Meta:
model = Case
fields = '__all__'
如果 ConfigSerializer
在 CaseSerializer
的 下方,那么 config = ConfigSerializer()
会报错
已经展示了config
嵌套字段
{
"msg": "success",
"retcode": 200,
"retlist": [
{
"id": 1,
"config": {
"id": 1,
"name": "用例1",
"base_url": "http://localhost",
"variables": null,
"parameters": null,
"verify": false,
"export": null
},
"file_path": "haiwen_Test.yml",
"suite": null
}
]
}
2. displayname
获取 method 具体的值:
# serializers.py
# 请求模型的序列化器
class RequestSerializer(serializers.ModelSerializer):
method = serializers.SerializerMethodField() # 自定义字段序列化返回方法
def get_method(self, obj): # rest 框架获取 method 时,自动调用该方法
return obj.get_method_display() # 返回 choice 的 displayname 而不是实际值
class Meta:
model = Request # 指定对应的模型
fields = '__all__' # 显示对应模型的所有字段
重新访问接口,method 字段返回了可读内容