首页 > Windows开发 > 详细

rest_framework的APIView的执行流程

时间:2020-07-06 21:41:31      阅读:63      评论:0      收藏:0      [点我收藏+]

rest_framework的APIView的执行流程

  • 1、项目运行时,优先执行路由层中的APIView下的as_view方法(会将类作为第一个参数传入),其内部调用了父类View的as_view方法,然后用变量view来接收父类as_view方法返回的内层函数view的内存地址,因为函数也是对象,因此可以通过对象.属性的方式赋值将类添加到内层函数view中(view.cls=cls),最后用csrf_exempt()来局部取消csrf认证,并且返回view

    # APIView内的as_view方法
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs) # 调用父类View中的as_view()
        view.cls = cls # 对象.属性的方式进行赋值,将类cls传入内层函数view中
        view.initkwargs = initkwargs
        return csrf_exempt(view) # csrf_exempt()局部取消csrf认证
    
  • 2、当请求来时,会自动触发内层函数view的执行,并且将wsgi封装好的request作为参数传入,会先实例化类(cls)的对象(self)(前面已经通过对象.属性的方法传入了)然后会调用对象(self)的dispatch方法并将request作为第一个参数传入,最后将结果返回

    def view(request, *args, **kwargs):
        # 实例化你定义的类cls,获得对象self
        self = cls(**initkwargs)
        # 调用对象的dispatch方法,调用父类APIView的dispatch方法,将对象跟request作为参数传入
        return self.dispatch(request, *args, **kwargs)
    
  • 3、调用对象的initialize_request方法,将原生的request传入,该方法会返回一个Request类的实例化对象,从而对原生request进行封装,并且增加了data属性,Request类中还封装了__getattr__方法,我们可以直接request.属性的方式来获取值(与我们操作原生request对象没有任何区别,唯一不同的就是此时的request已经不是原来的request了而是rest_framework的Requerst类生成的新的request对象,但是我们仍可以通过request._request来获取原生的request)

    # Request类的部分源码
    class Request:
        def __init__(self, request, parsers=None, authenticators=None,
                     negotiator=None, parser_context=None):
            # 原生的request
            self._request = request
            self._data = Empty # 空字典
            self._full_data = Empty
            self._files = Empty
        
        @property
        def FILES(self):
            # 可直接通过request.FILES获取文件(用法与原生request相同)
            if not _hasattr(self, ‘_files‘):
                self._load_data_and_files()
            return self._files
        
        @property
        def data(self):
            # 可以接收post请求任意编码传过来的数据,比原生request牛逼(返回一个字典)
            """
            我们可以使用request.data来获取post请求提交的数据
            可以使用request.query_params来获取get请求传过来的数据,返回结果也是一个字典
            可以使用request.FILES来获取文件数据
            """
            if not _hasattr(self, ‘_full_data‘):
                self._load_data_and_files()
            return self._full_data
        
        def __getattr__(self, attr):
            # 点拦截,当我们使用对象.属性时就会优先触发该方法
            try:
                # 通过反射将原生request内的方法反射出去
                # (因此我们无需对象._request.POST,直接使用对象.POST即可)
                return getattr(self._request, attr)
            except AttributeError:
                # 如果反射没有找到就使用下面的方法找,再找不到才报错
                return self.__getattribute__(attr)
    
    
    • 4、这个时候我们就可以用变量request来接收Request类实例化产生得对象了,之后我们再将这个新得request赋值给我们自己定义的类实例化的对象,然后再走APIView的三大认证组件。最后再校验请求方式,然后根据请求发起的对象不同返回不同的结果,如果是浏览器,那么就是返回html页面进行渲染,如果是postman,那么就会返回json格式的数据
    # APIView中的dispatch方法
        def dispatch(self, request, *args, **kwargs):
            # 此时的request已经不是原生的request了而是rest_framework的Request类实例化的对象,原生的request已经被封装在该request对象内了
            request = self.initialize_request(request, *args, **kwargs)
            # 将新得request对象通过对象.属性的方式赋值给了前面实例化类cls产生的self对象了(就是你自己定义的类实例化产生的那个对象)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                # 经过APIView的三大认证组件(认证组件、权限组件、频率组件)
                self.initial(request, *args, **kwargs)
    
                # 最后才来到请求方式校验,将请求方式与http_method_names列表内给定的请求方式匹配
                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
    			# 将内存地址加括号调用并且将新的request作为参数传入就相当于直接调用了我们定义的类中的方法
                response = handler(request, *args, **kwargs)
    
            except Exception as exc:
                response = self.handle_exception(exc)
    		# 根据请求发起的对象不同返回不同的结果,如果是浏览器,则返回html页面进行渲染,如果是postman,则返回json格式的数据
            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)

Restful规范

什么是Restful规范?

Restful规范就是一个定义web api接口的规范,它及其适用于前后端分离的情况

Resetful规范十条

  1. 数据的安全保障:推荐采用https协议,提高数据交互时的安全性
  2. 接口的特征表现:便于人一眼就看出这是一个接口,推荐使用api关键字表示接口url
  3. 多数据版本共存:当需要改变接口内容时不要直接修改已经运作的接口而是得重新写一个新得接口作为原来的接口的升级版,并且再url中标识出数据的版本(api/v1 api/v2)
  4. 数据即资源接口作为前后端交互的媒介其交互的数据又被叫做资源,推荐使用名词或者名词的复数形式,对于某些特殊接口,我们可以使用动词(api/books api/login)
  5. 资源操作由请求方式决定:资源的操作我们直接通过提交的请求方式来决定(get、post、put/patch、delete)
  6. 过滤:我们可以再url上传参的形式传递搜索条件
  7. 响应状态码:200、201(创建成功)、301(永久重定向)、302(临时重定向)、403(请求无权限)、404(请求路径不存在)、405(请求方法不存在)、500(服务器异常)
  8. 错误处理:应当返回错误信息
  9. 返回结果:更具不同的请求以及请求得到的数据返回不同的结果
  10. 需要url请求的资源需要访问资源的请求链接:返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么

rest_framework的APIView的执行流程

原文:https://www.cnblogs.com/guanxiying/p/13257191.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!