(day71)APIView生命请求周期、请求模块、解析模块、响应模块、渲染模块、异常模块

目录

一、APIView

(一)APIView源码

  1. APIView类继承View类,重写了as_view和dispatch方法
  2. 重写的as_view方法,主体还是View的as_view方法,只是再返回视图View函数地址时,局部禁用了csrf认证
  3. 重写的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请求生命周期

  1. APIView的as_view局部禁用csrf后走父类View的as_view方法调用self.dispatch方法
  2. 根据查找顺序,调用自己的dispatch方法分发请求,
  3. 重写的dispatch方法中在分发请求前,对request进行了二次封装和数据解析(请求模块和解析模块)
  4. 三大认证(认证、权限、频率)
  5. 执行请求方式对应的视图函数
  6. 出现异常,异常模块捕捉并处理
  7. 响应模块中二次封装response后完成响应,并通过渲染模块渲染(json或浏览器两种方式)

(day71)APIView生命请求周期、请求模块、解析模块、响应模块、渲染模块、异常模块

二、DRF的请求模块

  1. 经wsgi的request对象转化成drf的Reques对象
  2. 封装后的request对象完全兼容wsgi的request对象,并且将wsgi的request保存在drf的request的_request属性中

  3. drf的Request对象是在wsgi的reuqest基础上再次封装
  4. wsgi的request保存到drf的request的一个属性:_request中
  5. drf的request对wsgi的request做了完全兼容(request.GET同样可以获取数据)
  6. drf的request对数据解析更规范化,所有的拼接参数都解析到query_params中,所有数据包参数都被解析到data中
    • query_params和data属于QueryDict类型,DRF提供了一个.dict()的方法,可以将其转换成原生dict类型
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)

  1. 全局配置所有视图类的解析方式,解析配置可以配置三种
  2. 局部配置当前视图类的解析方式,解析配置可以配置三种
  3. 配置文件的查找顺序:局部(视图类的类属性)>全局(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'
    ],
}

(二)自定义配置解析模块

  1. JSONParser:对应application/json格式
  2. FormParser:对应application/x-www-form-urlencoded格式
  3. 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]


四、响应模块

(一)源码分析

  1. data:响应数据
  2. status:响应的网络状态码
  3. template_name:drf完成前后台不分离绑定页面、但是使用后就不可以返回data
  4. headers:响应头,一般不规定,默认
  5. exception:一般异常响应,会将其设置成True,默认False(不设置也可以)
  6. 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,
        )

五、渲染模块

  1. 默认Postman请求结果是json格式数据,浏览器请求结果是页面(上线后尽量关闭)
  2. 可以全局与局部配置,配置方式和解析模块相同
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]

六、异常模块

(一)源码分析

  1. context中封装了视图对象和请求对象

  2. 默认的exception_handler函数只处理客户端异常形成的response对象,服务器异常不作处理,返回none,一些其他类似语法错误由pycharm解释器捕捉提供

  3. 异常处理函数的配置路径:

    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

(二)自定义异常函数

  1. 新建文件定义异常函数
  2. 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',
}
上一篇:drf请求模块分析


下一篇:探索drf执行流程之APIView源码分析