zoukankan      html  css  js  c++  java
  • drf的请求生命周期, drf的解析模块, 响应模块, 渲染模块, 请求模块, 异常模块

    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_projd_projsettings.py
    # 注册
    INSTALLED_APPS = [
        ...,
    
        'rest_framework',
    
        ...
    ]
    
    # drf框架自定义配置
    REST_FRAMEWORK = {
    	...
    }
    '''
    

    django的Jsonresponse: from django.http import JsonResponse, 只能返回字典类型的数据

    drf的Response: from rest_framework.response import Response, 可以返回多种类型的数据

    基于drf的请求生命周期

    1. APIView类继承View类, 在APIView类中重写了as_view和dispatch方法
    2. 重写的as_view方法, 主体还是View中的as_view方法, 只是在返回view函数地址时, 局部禁用了csrf认证
    3. 重写的dispatch方法
      1. 在执行逻辑前: 请求模块二次封装request, 解析模块(三种数据包格式的数据解析)
      2. 在执行逻辑时: 执行出现任何异常交给异常模块处理
      3. 在执行逻辑后: 响应模快二次封装response, 渲染模块(响应的数据能JSON和页面两种模式渲染)

    dispatch

    '''
    # G:python-3.6.4-64Libsite-packagesdjangoviewsgenericase.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-64Libsite-packages
    est_frameworkviews.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_projapiviews.py
      from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
      
      
      class BookAPIView(APIView):
          parser_classes = [JSONParser, FormParser, MultiPartParser]
      
          ...
      '''
      
    • 全局配置所有视图类的解析方式

      # C:...d_projd_projsettings.py
      # drf框架自定义配置
      REST_FRAMEWORK = {
          'DEFAULT_PARSER_CLASSES': [
              'rest_framework.parsers.JSONParser',
              'rest_framework.parsers.FormParser',
              'rest_framework.parsers.MultiPartParser'
          ],
      }
      
    • 所有视图类的默认解析方式

      '''
      # G:...
      est_frameworksettings.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:...
    est_frameworkviews.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:...
    est_framework
    equest.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:...
    est_frameworksettings.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_projapiviews.py
      from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
      
      
      class BookAPIView(APIView):
          renderer_classes = [BrowsableAPIRenderer, JSONRenderer]
          ...
      '''
      
    • 全局配置

      # C:...d_projd_projsettings.py
      # drf框架自定义配置
      REST_FRAMEWORK = {
          ...
          'DEFAULT_RENDERER_CLASSES': [
              'rest_framework.renderers.JSONRenderer',
              'rest_framework.renderers.BrowsableAPIRenderer',
          ],
      }
      
    • drf默认配置

      '''
      # G:...
      est_frameworkviews.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)
      '''
      

    请求模块

    1. 将wsgi的request对象转换成drf的Request类的对象
    2. 封装后的request对象完全兼容wsgi的request对象, 并且将原request对象保存在新request对象的_request属性中
    3. 重新格式化请求数据的存放位置
      • 拼接参数: request.query_params---@property执行方法属性, 给request._request.method重新命名
      • 数据包参数: request.data---@property执行方法属性, 值依赖于request._full_data
    4. request.method, 通过在Request类中自定义 __getattr__ 方法优先从request._request中查找
    '''
    # G:...
    est_frameworkviews.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:...
    est_framework
    equest.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_projapiexception.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_projd_projsettings.py
      REST_FRAMEWORK = {
          ...,
          'EXCEPTION_HANDLER': 'api.exception.exception_handler',
      }
      '''
      
    '''
    G:...
    est_frameworkviews.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:...
    est_frameworksettings.py
    DEFAULTS = {  
        ...,
        # Exception handling
        'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',  # drf框架中异常模块的默认配置
        ...,
    }
    api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
    '''
    
  • 相关阅读:
    路由守卫
    this.$nextTick() 的一些理解
    3d饼图
    element ui 可编辑的表格
    vue 路由传参
    vue+element ui 时间格式化
    element ui 选择期 传对象
    数据结构学习第十天
    数据结构学习第九天
    数据结构学习第八天
  • 原文地址:https://www.cnblogs.com/-406454833/p/12118340.html
Copyright © 2011-2022 走看看