drf简介
封装规范
'''
from rest_framework.views import APIView
from rest_framework.views import Request
from rest_framework.views import Response
from rest_framework.exceptions import APIException
from rest_framework.pagination import PageNumberPagination
from rest_framework.settings import APISettings
from rest_framework.parsers import JSONParser
from rest_framework.filters import OrderingFilter
'''
drf配置
'''
# d_proj\d_proj\settings.py
# 注册
INSTALLED_APPS = [
...,
'rest_framework',
...
]
# drf框架自定义配置
REST_FRAMEWORK = {
...
}
'''
django的Jsonresponse: from django.http import JsonResponse
, 只能返回字典类型的数据
drf的Response: from rest_framework.response import Response
, 可以返回多种类型的数据
基于drf的请求生命周期
- APIView类继承View类, 在APIView类中重写了as_view和dispatch方法
- 重写的as_view方法, 主体还是View中的as_view方法, 只是在返回view函数地址时, 局部禁用了csrf认证
- 重写的dispatch方法
- 在执行逻辑前: 请求模块二次封装request, 解析模块(三种数据包格式的数据解析)
- 在执行逻辑时: 执行出现任何异常交给异常模块处理
- 在执行逻辑后: 响应模快二次封装response, 渲染模块(响应的数据能JSON和页面两种模式渲染)
'''
# G:\python-3.6.4-64\Lib\site-packages\django\views\generic\base.py
class View(object):
...
@classonlymethod
def as_view(cls, **initkwargs):
...
def view(request, *args, **kwargs): # view只是一个普通函数, 既不是类的绑定方法, 也不是对象的绑定方法, 接收request, 无名分组参数, 有名分组参数
self = cls(**initkwargs) # 此时的cls为调用as_view方法的类, 即class BookAPIView, self为BookAPIView实例化出来的对象
...
return self.dispatch(request, *args, **kwargs) # BookAPIView实例化出来的对象调用dispatch方法, 将request, 无名分组参数, 有名分组参数传入dispatch
...
return view
# G:\python-3.6.4-64\Lib\site-packages\rest_framework\views.py
class APIView(View):
...
@classmethod
def as_view(cls, **initkwargs):
...
view = super().as_view(**initkwargs) # 重用父类View的as_view方法
...
return csrf_exempt(view) # 局部禁用csrf认证
def dispatch(self, request, *args, **kwargs): # 该方法被BookAPIView实例化出来的对象调用, self参数即为该对象
...
request = self.initialize_request(request, *args, **kwargs) # 二次封装request对象
self.request = request
try:
self.initial(request, *args, **kwargs) # 三大认证(认证, 权限, 频率), 用来替换csrf认证
...
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc) # 异常模块, 处理请求异常分支
self.response = self.finalize_response(request, response, *args, **kwargs) # 二次封装response对象
return self.response
'''
解析模块
只处理数据包参数: form-data, form-urlencoded, json
-
局部配置当前视图类的解析方式
''' # C:\...\d_proj\api\views.py from rest_framework.parsers import JSONParser, FormParser, MultiPartParser class BookAPIView(APIView): parser_classes = [JSONParser, FormParser, MultiPartParser] ... '''
-
全局配置所有视图类的解析方式
# C:\...\d_proj\d_proj\settings.py # drf框架自定义配置 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ], }
-
所有视图类的默认解析方式
''' # G:\...\rest_framework\settings.py api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) DEFAULTS = { # drf的settings.py中的默认配置 ..., 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ], ... } '''
配置的查找顺序
局部(自定义的CBV中)-->全局(django项目的setting.py中)-->默认(drf的settings.py中)
'''
# G:\...\rest_framework\views.py
class APIView(View):
...
parser_classes = api_settings.DEFAULT_PARSER_CLASSES # 优先从django项目的settings文件中查找解析模块, 然后从drf的settings文件中查找
...
def dispatch(self, request, *args, **kwargs): # dispatch方法被BookAPIView实例化出来的对象调用, self参数即为该对象
...
request = self.initialize_request(request, *args, **kwargs) # 重新初始化wsgi封装的request对象, 得到新的request
...
def initialize_request(self, request, *args, **kwargs):
...
parser_context = self.get_parser_context(request) # 获取解析数据
return Request( # 在Request模块中通过解析模块处理wsgi封装的request对象
request,
parsers=self.get_parsers(), # 获取解析对象
...
parser_context=parser_context
)
def get_parser_context(self, http_request):
...
return { # 将解析数据拆解到字典中
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {})
}
def get_parsers(self): # self为BookAPIView实例化出来的对象
...
return [parser() for parser in self.parser_classes] # 优先查找BookAPIView及其对象的名称空间
# G:\...\rest_framework\request.py
class Request:
...
def __init__(self, request, parsers=None, ..., parser_context=None): # 初始化Request类的自定义属性
...
self._request = request
...
self.parser_context = parser_context
...
self._full_data = Empty
...
# G:\...\rest_framework\settings.py
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
DEFAULTS = { # drf的settings.py中的默认配置
...,
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
...
}
'''
响应模块及渲染模块
响应模块
data: 响应数据
status: 响应状态码
'''
def post(self, request, *args, **kwargs):
...
response = Response(
data={
'msg': 'api view post ok',
},
status=404
)
return response
'''
渲染模块
postman请求结果是json, 浏览器请求结果是页面
-
局部配置
''' # C:\...\d_proj\api\views.py from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer class BookAPIView(APIView): renderer_classes = [BrowsableAPIRenderer, JSONRenderer] ... '''
-
全局配置
# C:\...\d_proj\d_proj\settings.py # drf框架自定义配置 REST_FRAMEWORK = { ... 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], }
-
drf默认配置
''' # G:\...\rest_framework\views.py class APIView(View): ... renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES ... # DEFAULTS = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ], ... } ... api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) '''
请求模块
- 将wsgi的request对象转换成drf的Request类的对象
- 封装后的request对象完全兼容wsgi的request对象, 并且将原request对象保存在新request对象的_request属性中
- 重新格式化请求数据的存放位置
- 拼接参数: request.query_params---@property执行方法属性, 给request._request.method重新命名
- 数据包参数: request.data---@property执行方法属性, 值依赖于request._full_data
- request.method, 通过在Request类中自定义
__getattr__
方法优先从request._request中查找
'''
# G:\...\rest_framework\views.py
class APIView(View):
def dispatch(self, request, *args, **kwargs):
...
request = self.initialize_request(request, *args, **kwargs)
...
def initialize_request(self, request, *args, **kwargs):
...
return Request(
request,
...
)
# G:\...\rest_framework\request.py
class Request:
...
def __init__(self, request, ...):
...
self._request = request
...
self._full_data = Empty
...
@property
def query_params(self):
...
return self._request.GET
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data # 将三种类型的数据包参数解析到._full_data中
...
def __getattr__(self, attr):
...
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
'''
异常模块
-
自定义异常处理配置: 1. 在api文件夹中新建exception.py文件; 2. 在项目的settings.py中进行相关配置
''' C:\...\d_proj\api\exception.py from rest_framework.response import Response from rest_framework.views import exception_handler as drf_exception_handler def exception_handler(exc, context): response = drf_exception_handler(exc, context) detail = '%s - %s - %s' % (context.get('view'), context.get('request').method, exc) if not response: # 后端错误 response = Response({'detail': detail}, 500) # 响应模块初始化实例时数据传入第一个默认形参data中 else: response.data = {'detail': detail} # 重写前端异常时的响应信息 return response # 核心: 后端在返回response前需要将异常信息记录到日志 # C:\...\d_proj\d_proj\settings.py REST_FRAMEWORK = { ..., 'EXCEPTION_HANDLER': 'api.exception.exception_handler', } '''
'''
G:\...\rest_framework\views.py
class APIView(View):
settings = api_settings # settings指向配置文件
def dispatch(self, request, *args, **kwargs):
...
try:
self.initial(request, *args, **kwargs) # 三大认证校验
if request.method.lower() in self.http_method_names: # 前端请求方式判断
handler = getattr(self, request.method.lower(), # handler句柄指向对应的视图类中的对应方法
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed # handler句柄指向前端抛错函数
response = handler(request, *args, **kwargs) # 执行handler句柄指向的函数, 并将结果封装到response总
except Exception as exc: # exc能捕获的异常信息来源于三大认证过程以及执行handler句柄指向的函数的过程
response = self.handle_exception(exc) # 处理异常信息并将处理结果封装到response中
...
def http_method_not_allowed(self, request, *args, **kwargs): # 对应前端请求方式错误
...
raise exceptions.MethodNotAllowed(request.method)
def handle_exception(self, exc): # 处理多种类型的异常
...
exception_handler = self.get_exception_handler() # 获取处理异常的方法
context = self.get_exception_handler_context() # 获取异常处理的额外参数
response = exception_handler(exc, context)
if response is None:
self.raise_uncaught_exception(exc)
response.exception = True
return response
def get_exception_handler(self):
return self.settings.EXCEPTION_HANDLER # 从配置文件中导入异常处理的相关数据
def get_exception_handler_context(self):
...
return {
'view': self, # 处理当前前端请求的类的实例化对象
'args': getattr(self, 'args', ()), # 匹配url得到的无名分组
'kwargs': getattr(self, 'kwargs', {}), # 匹配url得到的有名分组
'request': getattr(self, 'request', None) # 二次封装后的request
}
def exception_handler(exc, context):
... # 处理前端异常
return Response(data, status=exc.status_code, headers=headers)
return None # 后端异常返回None
# G:\...\rest_framework\settings.py
DEFAULTS = {
...,
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', # drf框架中异常模块的默认配置
...,
}
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
'''