zoukankan      html  css  js  c++  java
  • CBV源码与APIView源码解析

    一、CBV源码解析

    在我们写cbv的时候在url中和fbv的区别就是是否调用了as_view()方法,所以关键入手点就是这个方法

    @classonlymethod
    	# 这是类的绑定方法,这个cls是我们创造的类
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            # self是在实例化一个对象
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                # 关键在dispatch内
                return self.dispatch(request, *args, **kwargs)
         return view
            
    
            def dispatch(self, request, *args, **kwargs):
               # http_method_names是一个存放了所有请求方式的列表
                if request.method.lower() in self.http_method_names:
                    # 用到了反射的方法吗,如果CBV中我们写了这个请求的方法,就把他赋值给handler,如果没有就返回一个not_allowed
                    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
                    else:
                        handler = self.http_method_not_allowed
                        return handler(request, *args, **kwargs)
    

    二、APIView源码解析

    apiview同样关键点在as_view中

     @classmethod
        def as_view(cls, **initkwargs):、
            # 继承了父类View的as_view的调用结果,就是父类的view
        	view = super().as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
            # 这是调用了屏蔽csrf检测的装饰器
            return csrf_exempt(view)
       	# 这里要注意区分,return中的view,其实就是父类中的view
        
            def view(request, *args, **kwargs):          
                    # 关键还是在dispatch内
                    # 注意此刻dispatch的查找顺序,定义的类中没有,去父类APIView中找,我们发现了新的dispatch方法
                    return self.dispatch(request, *args, **kwargs)
        
    # APIView的dispatch方法
        def dispatch(self, request, *args, **kwargs):
    
            self.args = args
            self.kwargs = kwargs
            # 重新包装成一个request对象,以后再用的request对象,就是新的request对象了
            request = self.initialize_request(request, *args, **kwargs)
            self.request = 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
    
                # 响应模块,调用请求函数得到一个响应对象,此时内部存放的是json数据
                response = handler(request, *args, **kwargs)
    			
            except Exception as exc:
                # 异常模块
                response = self.handle_exception(exc)
    
            # 渲染模块,我们能在前端看到api的html页面,就是这里做的
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response 
        
        # APIView的initial方法,认证模块
     	def initial(self, request, *args, **kwargs):
            # 认证组件:校验用户 - 游客、合法用户、非法用户
            # 游客:代表校验通过,直接进入下一步校验(权限校验)
            # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
            # 非法用户:代表校验失败,抛出异常,返回403权限异常结果
            self.perform_authentication(request)
            # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
            # 认证通过:可以进入下一步校验(频率认证)
            # 认证失败:抛出异常,返回403权限异常结果
            self.check_permissions(request)
            # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
            # 没有达到限次:正常访问接口
            # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
            self.check_throttles(request)
            
        # 我们再看看新赋值的request内部是什么
        def initialize_request(self, request, *args, **kwargs):
            """
            Returns the initial request object.
            """
            parser_context = self.get_parser_context(request)
    
            return Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
        # 再点击Request,我们发现原来的request被封装给_request了,之后使用request都是在原来基础上新造的
        # 原来的request都是.属性的,所以我们可以很肯定这里重写了点拦截方法(__getattr__)
        def __getattr__(self, attr):
            try:
                return getattr(self._request, attr) #通过反射,取原生的request对象,取出属性或方法
            except AttributeError:
                return self.__getattribute__(attr)
    

    APIView还给我们做了一件事情,因为我们后面在通过api进行数据交互的时候用的都是json格式的数据,但是django默认不会处理json格式的数据,所以这里他新定义的request有一个data方法

    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
            return self._full_data
    

    他还重新定义了GET的名字,我们本来拿到get请求来的数据应该是django.GET来的,但是由于我们是查找数据,这样的名字不够见名知意所以,

        @property
        def query_params(self):
            """
            More semantically correct name for request.GET.
            """
            return self._request.GET
    

    用request.query_params来替代request.GET,当然由于之前重写request的时候用了反射的方法把原生request的方法属性全都赋值给了新的request所以GET也是能用的

  • 相关阅读:
    LeetCode Path Sum II
    LeetCode Longest Palindromic Substring
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Binary Tree Maximum Path Sum
    LeetCode Find Peak Element
    LeetCode Maximum Product Subarray
    LeetCode Intersection of Two Linked Lists
    一天一个设计模式(1)——工厂模式
    PHP迭代器 Iterator
  • 原文地址:https://www.cnblogs.com/hz2lxt/p/13257266.html
Copyright © 2011-2022 走看看