目录
一、APIView
(一)APIView源码
- APIView类继承View类,重写了as_view和dispatch方法
- 重写的as_view方法,主体还是View的as_view方法,只是再返回视图View函数地址时,局部禁用了csrf认证
- 重写的dispatch方法中:
- 在执行请求逻辑前:请求模块(二次封装request)、解析模块(三种数据包格式的数据解析)
- 在执行请求逻辑中:异常模块(处理异常)
- 在执行请求逻辑后:响应模块(二次封装response)、渲染模块(两种渲染模式)
class APIView(View):
@classmethod
def as_view(cls, **initkwargs):
# 核心,走了父类View类的as_view
view = super().as_view(**initkwargs)
# 局部禁用csrf认证,使用
return csrf_exempt(view)
def dispatch(self, request, *args, **kwargs):
# 请求模块:二次封装request对象,包含解析模块
request = self.initialize_request(request, *args, **kwargs)
try: # 请求逻辑
# 三大认证(认证、权限、频率),用来替换csrf安全认证,比csrf强大
self.initial(request, *args, **kwargs)
except Exception as exc:
# 异常模块:处理请求异常
response = self.handle_exception(exc)
# 响应模块:二次封装response,包含渲染模块(json或浏览器两种方式)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
(二)APIView请求生命周期
- APIView的as_view局部禁用csrf后走父类View的as_view方法调用
self.dispatch
方法 - 根据查找顺序,调用自己的dispatch方法分发请求,
- 重写的dispatch方法中在分发请求前,对request进行了二次封装和数据解析(请求模块和解析模块)
- 三大认证(认证、权限、频率)
- 执行请求方式对应的视图函数
- 出现异常,异常模块捕捉并处理
- 响应模块中二次封装response后完成响应,并通过渲染模块渲染(json或浏览器两种方式)
二、DRF的请求模块
- 经wsgi的request对象转化成drf的Reques对象
封装后的request对象完全兼容wsgi的request对象,并且将wsgi的request保存在drf的request的_request属性中
- drf的Request对象是在wsgi的reuqest基础上再次封装
- wsgi的request保存到drf的request的一个属性:_request中
- drf的request对wsgi的request做了完全兼容(request.GET同样可以获取数据)
- drf的request对数据解析更规范化,所有的拼接参数都解析到query_params中,所有数据包参数都被解析到data中
- query_params和data属于QueryDict类型,DRF提供了一个
.dict()
的方法,可以将其转换成原生dict类型
- query_params和data属于QueryDict类型,DRF提供了一个
class APIView(View):
# 二次封装request
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request) # 获取解析内容,包装视图成字典
# 1. drf的Request对象是在wsgi的reuqest基础上再次封装
return Request(
request,
parsers=self.get_parsers(), # 获取解析类型(三大类型)
authenticators=self.get_authenticators(), # 获取认证类型
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
# 2. 将wsgi的request封装到drf的request中的_request属性中
self._request = request
def __getattr__(self, attr):
try:
# 3. drf的request对wsgi的request做了完全兼容
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
# 将拼接参数都解析到query_params中
@property
def query_params(self):
return self._request.GET
# 将数据包参数都被解析到data中,涉及到渲染模块
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
三、解析模块
(一)源码分析
只处理数据包参数(form-data、urlencoded和json)
- 全局配置所有视图类的解析方式,解析配置可以配置三种
- 局部配置当前视图类的解析方式,解析配置可以配置三种
- 配置文件的查找顺序:局部(视图类的类属性)>全局(settings文件的drf配置)>默认(drf的默认配置)
class APIView(View):
# 默认配置解析的类型
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
# 查找解析模式
def get_parsers(self):
# 查找parser_classes配置文件
return [parser() for parser in self.parser_classes]
# rest_framework/settings.py文件中(默认配置)
DEFAULTS = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
}
(二)自定义配置解析模块
- JSONParser:对应
application/json
格式 - FormParser:对应
application/x-www-form-urlencoded
格式 - MultiPartParser:对应
multipart/form-data
格式
# 1. setting.py文件中(全局配置)
REST_FRAMEWORK={
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
],
}
# 2. api/view.py文件中(局部配置)
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookAPIView(APIView):
parser_classes = [JSONParser,FormParser,MultiPartParser]
四、响应模块
(一)源码分析
- data:响应数据
- status:响应的网络状态码
- template_name:drf完成前后台不分离绑定页面、但是使用后就不可以返回data
- headers:响应头,一般不规定,默认
- exception:一般异常响应,会将其设置成True,默认False(不设置也可以)
- content_type:默认就是application/json,不需要处理
# rest_framework/response.py
class Response(SimpleTemplateResponse): # 最终继承Django的response
def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):···
# 渲染模块入口
@property
def rendered_content(self):···
(二)status自定义实例
# api.views.py
from rest_framework import status
class BookAPIView(APIView):
def get(self, request, *args, **kwargs):
response = Response(
data={
'msg': 'apiview get ok'
},
status=status.HTTP_404_NOT_FOUND,
)
五、渲染模块
- 默认Postman请求结果是json格式数据,浏览器请求结果是页面(上线后尽量关闭)
- 可以全局与局部配置,配置方式和解析模块相同
class APIView(View):
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
# rest_framework/settings.py文件中(默认配置)
DEFAULTS = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 1. setting.py文件中(全局配置)
REST_FRAMEWORK={
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 2. api/view.py文件中(局部配置)
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
class BookAPIView(APIView):
# 局部配置渲染类:只适用当前视图类
renderer_classes = [JSONRenderer, BrowsableAPIRenderer]
六、异常模块
(一)源码分析
context中封装了视图对象和请求对象
默认的exception_handler函数只处理客户端异常形成的response对象,服务器异常不作处理,返回none,一些其他类似语法错误由pycharm解释器捕捉提供
-
异常处理函数的配置路径:
DEFAULTS = {'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',}
# 逻辑代码
class APIView(View):
def handle_exception(self, exc):
# 三大认证相关异常,额外处理响应头,返回403错误
if isinstance(exc,(exceptions.NotAuthenticated,exceptions.AuthenticationFailed)):···
# 获取处理异常的函数
exception_handler = self.get_exception_handler()
# 给异常处理提供额外的参数,将视图对象view和请求对象封装到content中
context = self.get_exception_handler_context()
response = exception_handler(exc, context) # 将异常信息exc和content字典传递给处理异常函数执行
# 默认的exception_handler函数只处理客户端异常形成的response对象,服务端异常不作处理,返回none
if response is None:
self.raise_uncaught_exception(exc)
response.exception = True
return response
# 封装异常处理所需要的参数,
def get_exception_handler_context(self):
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {}),
'request': getattr(self, 'request', None)
}
# 处理异常的函数
def get_exception_handler(self):
return self.settings.EXCEPTION_HANDLER
# 配置文件
# rest_framework/settings.py
DEFAULTS = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
}
# rest_framework/views.py中处理异常函数
# 默认的exception_handler函数只处理客户端异常形成的response对象,服务器端异常不作处理,返回none
def exception_handler(exc, context):
if isinstance(exc, Http404):···
elif isinstance(exc, PermissionDenied):···
if isinstance(exc, exceptions.APIException):···
return None
(二)自定义异常函数
- 新建文件定义异常函数
- settings文件中配置异常函数路径
- 默认异常函数只捕捉客户端错误,因此自定义中,将服务端错误信息也封装到response对象中,方便开发人员debug
- 在开发过程中,可以将客户端错误对应的视图对象和请求方式封装到data中,方便开发人员debug
- 在实际开发中,通常会把所有的错误都记录成logging日志,方便查看
# api/exception.py
# 一定要在settings文件中将异常模块配置自己的异常处理函数
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
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})
else:
response.data = {'detail': detail} # 封装客户端错误的详细信息
# 核心:要将response.data.get('detail')信息记录到日志文件
# logger.waring(response.data.get('detail'))
return response
# settings.py文件中
REST_FRAMEWORK = {
# 异常模块:异常处理函数
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'EXCEPTION_HANDLER': 'api.exception.exception_handler',
}