zoukankan      html  css  js  c++  java
  • DRF的APIView源码分析

    DRF的APIView源码分析

    DRF框架中的APIView继承于django框架的View

    class APIView(View):
    

    urls.py

    from app01 import views
    
    urlpatterns = [
        path('books/<int:book_id>/', views.Books.as_view(), name='books'),
    ].py
    

    views.py

    from rest_framework.views import APIView
    

    APIView重写了View的as_view方法

    @classmethod
    def as_view(cls, **initkwargs): # cls是Book类
        ...
        view = super().as_view(**initkwargs) #调用了父类View的as_view方法
        view.cls = cls  # 一切皆对象,将cls赋值给View的cls属性
        view.initkwargs = initkwargs
    
        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view) # 去除掉CSRF认证
    

    View的as_view方法

    def as_view(cls, **initkwargs):
        ...
        def view(request, *args, **kwargs): # 闭包函数
            self = cls(**initkwargs)  #  实例化book类的对象
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            
            return self.dispatch(request, *args, **kwargs)
        return view
    

     分发函数dispatch

    # 这里调用分发函数dispatch是APIVIEW的(查找顺序,先对象中,后类中,在父类中)
    
    # APIVIEW的dispatch方法
    def dispatch(self, request, *args, **kwargs):
        # request是原生的request
        self.args = args
        self.kwargs = kwargs
        # 这里将request对象进行了二次封装
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request # 将二次封装后的request赋值给book对象的request属性
        self.headers = self.default_response_headers  # deprecate?
    
        try:
            # 三大认证模块
            self.initial(request, *args, **kwargs)
    
            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            # 响应模块
            response = handler(request, *args, **kwargs) # get(request)
    
        except Exception as exc:
            # 异常捕获模块
            response = self.handle_exception(exc)
        # 渲染模块
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    
    

    看下initialize_request(request, *args, **kwargs)

    from rest_framework.request import Request
    
    def initialize_request(self, request, *args, **kwargs):
        ...
        return Request(
            request,
            parsers=self.get_parsers(),  #  参数解析
            authenticators=self.get_authenticators(), # 认证
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    

    使用DRF的request.Request对原生的request进行了二次的封装

    接着看下三大认证模块initial(self, request, *args, **kwargs)

    def initial(self, request, *args, **kwargs):
    
        # 版本控制
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme
    
        # Ensure that the incoming request is permitted
        self.perform_authentication(request) # 认证
        self.check_permissions(request)  # 权限校验
        self.check_throttles(request)  # 频率检测
    
    # 认证组件
    建议用户:合法用户,非法用户,游客
    # 游客:代表校验通过,直接进入下一步校验(权限校验)
    # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
    # 非法用户:代表校验失败,抛出异常,返回403权限异常结果
    
    # 权限组件
    权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
    # 认证通过:可以进入下一步校验(频率认证)
    # 认证失败:抛出异常,返回403权限异常结果
    
    # 频率组件
    限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
    
    # 没有达到限次:正常访问接口
    # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
    

    流程分析图:

    此外,DRF中通过重写__getattr__ 方法,通过反射getattr来访问原生的 request,取出属性以及方法

    # 原生的request被赋值给了self._request
     def __getattr__(self, attr):
            try:
                return getattr(self._request, attr) #通过反射,取原生的request对象,取出属性或方法
            except AttributeError:
                return self.__getattribute__(attr)
     # request.data 
    	@property,修饰了伪装属性
    	它是一个字典,post请求不管使用什么编码,传过来的数据,都request.data
     #get请求传过来数据,从哪取?
    	request.GET
        @property
        def query_params(self):
            return self._request.GET
        
        #视图类中
         print(request.query_params)  #get请求,地址中的参数
         # 原来在
         print(request.GET)
    
  • 相关阅读:
    SSAS aggregation 的作用及其使用
    liblinear使用总结
    python绝对路径相对路径函数
    libsvm使用总结
    一次scrapy成功停止的信息
    简单总结scrapy使用方法
    python编码格式
    一次scrapy失败的提示信息:由于连接方在一段时间后没有正确答复或连接的主机没有反 应,连接尝试失败
    17.1 MySQL主从介绍 17.2 准备工作 17.3 配置主 17.4 配置从 17.5 测试主从同步
    16.1 Tomcat介绍 16.2 安装jdk 16.3 安装Tomcat
  • 原文地址:https://www.cnblogs.com/surpass123/p/13258593.html
Copyright © 2011-2022 走看看