rest_framework --- APIView

2018-12-17 10:50:34来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

一、什么是rest_framework
    它是基于Django的,帮助我们快速开发符合RESTful规范的接口框架。
    安装方式有很多种,可以通过pip,或者在pycharm中安装也可以


二、APIView
    它的作用和from django.views import View中的View作用差不多,APIView是继承了View,所以执行as_view,dispatch方法都会
    先走到APIView这个类中。所以通过这个APIView里的dispatch进行一层封装,对request这个对象进行改变,添加了认证、权限、频率这些
    认证。可以去看看它的源码。
    视图层(CBV模式): class Login(APIView):
    路由层:url(r'login/',views.Login.as_views())

    分析:
        程序启动时:会执行一遍django中的代码,函数没有被调用的话,只会检测其语法是否正确,看到路由层views.Login.as_views(),这是
                  一个函数加了括号,所以会执行到,as_views这是一个由类去调用并没有传参数的函数,如果不是静态方法,就是一个类方法,
                  我Login这个类中没有as_views这个方法,所以去它的基类(APIView)去找,找到了

                as_view(cls,**initkwargs):
                    """
                    Store the original class on the view function.

                    This allows us to discover information about the view when we do URL
                    reverse lookups.  Used for breadcrumb generation.
                    """
                    if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
                        def force_evaluation():
                            raise RuntimeError(
                                'Do not evaluate the `.queryset` attribute directly, '
                                'as the result will be cached and reused between requests. '
                                'Use `.all()` or call `.get_queryset()` instead.'
                            )
                        cls.queryset._fetch_all = force_evaluation

                    view = super(APIView, cls).as_view(**initkwargs)
                    view.cls = cls
                    view.initkwargs = initkwargs

                    # Note: session based authentication is explicitly CSRF validated,
                    # all other authentication is CSRF exempt.
                    return csrf_exempt(view)

                # 这行代码 view = super(APIView, cls).as_view(**initkwargs),它会执行APIView基类(View)中的
                  as_view方法,得到一个函数的内存地址,赋值给view
                  最后return csrf_exempt(view)  #csrf_exempt()是不是局部禁用了csrf检测
        所以,在程序启动了之后,路由层的代码应该为url(r'login/',views.Login.csrf_exempt(view))
        # 注意其实这里不是最终的版本,他还会执行csrf_exempt(view),总之views.Login.csrf_exempt(view)的执行结果是一个函数的内存地址
        # csrf_exempt这个就是禁用掉csrf认证的装饰器吧,最后返回的还是view函数



        有请求来的时候:
        当有请求走到路由层时,那么该url对应的函数内存地址便会加括号直接运行,比如url为login,那么执行views.Login.view()
        通过上面as_view方法,我们不难找到view方法,APIView中的view,是调用其父类(View)as_view方法,而as_view返回值就是view的内存地址,
        那么view函数的源码就是下面这些,经过一些判断,最后返回的是dispatch方法的返回值
            def view(request, *args, **kwargs):
                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
                return self.dispatch(request, *args, **kwargs)
        view函数的返回值return self.dispatch(request, *args, **kwargs),这里的self其实就是Login(这个视图类的对象),所以我们的查找
        顺序为对象名称空间,然后就是它父类的名称空间,一层一层往上找,Login这个试图类是我们自己写的,如果自己没写dispatch方法的话,那应该就去
        它的基类(APIView)去找dispatch,我们可以在APIView类中可以看到有这个dispatch方法,下面列出源码:
            def dispatch(self, request, *args, **kwargs):
                """
                `.dispatch()` is pretty much the same as Django's regular dispatch,
                but with extra hooks for startup, finalize, and exception handling.
                """
                self.args = args
                self.kwargs = kwargs
                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

                    response = handler(request, *args, **kwargs)

                except Exception as exc:
                    response = self.handle_exception(exc)

                self.response = self.finalize_response(request, response, *args, **kwargs)
                return self.response


        dispatch方法主要看这几句:
            -----------------------------------------------------------
            request = self.initialize_request(request, *args, **kwargs)
            -----------------------------------------------------------
            self.initial(request, *args, **kwargs)
            -----------------------------------------------------------
            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)
            -----------------------------------------------------------


        ############
        好下面来说说注意的第一行代码:request = self.initialize_request(request, *args, **kwargs)
        ############
        # 我先说它做了什么事情,不看内部代码,将self(此时是Login视图类的对象),执行方法initialize_request方法的返回值赋值给了request,
        # 其实这句代码就是重新封装了request,方法传入的request对象其实就是没有被处理过的,经过一顿操作后,返回值request就是rest_framework
        # 中Request类的对象。下面是initialize_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就是rest_framework中的Request类了,括号里就是传过去的参数吧,这里self也是视图类
        的对象(Login),拿一个括号里的参数来讲,其他参数方式都是一样,就不一一解释了。
        比如这句:authenticators=self.get_authenticators()
            这句代码不难理解吧,直接self的get_authenticators绑定方法,也可能是静态方法,把返回值赋值给authenticators,我这里说静态是光看这
            一句代码可以看出。点进去看看get_authenticators源码如下:
                def get_authenticators(self):
                    """
                    Instantiates and returns the list of authenticators that this view can use.
                    """
                    return [auth() for auth in self.authentication_classes]
            最终返回的是一个列表,这里的self还是视图类对象(Login),authentication_classes这就是一个属性对吧,那么我们就去找找这个属性到底
            是什么,self为视图类对象,那我们先从视图类(Login)找属性,我们自己写的视图类没有的话,就去继承的APIView类中查看。就在该类的最前面部分
            有这样一段代码:authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES,那就继续按住ctrl,点击api_settings
            去查看呗,这句代码api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS),api_settings它是APISettings这个类的对象,
            你可以看到这个常量DEFAULTS,那么就在当前py文件搜索下,看看哪里出现过,最终肯定能找到,DEFAULTS它是一个字典,这个字典里就有很多key,
            value形式,我们不难找到DEFAULT_AUTHENTICATION_CLASSES这个key对吧:
                'DEFAULT_AUTHENTICATION_CLASSES': (
                            'rest_framework.authentication.SessionAuthentication',
                            'rest_framework.authentication.BasicAuthentication'
                        )
            rest_framework.authentication.SessionAuthentication,这样的形式我们是不是见过(settings文件中有很多)
            我们可以通过导模块的方式,看看这是什么。
            from rest_framework.authentication import SessionAuthentication
            可以看出,这是一个类,那么,我们倒着再理解下。注意:
                api_settings.DEFAULT_AUTHENTICATION_CLASSES ---->>>  是一个元组(列表也是) == [类,类,类]
                authentication_classes 这个属性也就是   ---->>>  是一个元组(列表也是) == [类,类,类]
            回到最初那个地方 [auth() for auth in self.authentication_classes],列表生成式不难理解,那么get_authenticators方法返回的
            就是[类(),类(),类()] ----->>>  也就是[对象,对象,对象],又回到Request对象的实例了
            authenticators=self.get_authenticators(),所以authenticators就是一个[对象,对象,对象],就是装着对象的列表。

        ######总结一下initialize_request这个方法:
               1、它最终返回的就是一个Request的对象,这里的Request不再是之前那个了,是rest_framework里的Request对象
               2、再看返回值这里,self.get_authenticators()最终得到是装着对象的列表,列表里的对象是视图类对象里的authentication_classes
                  这个属性得到的,而这个属性它是一个列表(元组也行),装着对应的类。

               提醒几点:注意你看的源码,当前的self是谁,还有就是面向对象属性的查找顺序。(先对象名称空间,它父类的名称空间,父类继承基类的名称空间
                       ,最后应该就是type吧(type这个的话,我理解是这样))



        ############
        那好继续下一句注意的代码,self.initial(request, *args, **kwargs)
        ############
        这行代码self.initial(request, *args, **kwargs),它主要做了登陆验证,权限验证,频率验证,如果一个请求都满足上面这些这些验证的话,
        那么就会执行到对应的请求方法里面,比如来一个get请求,那就走到该视图类get方法中去
        下面是self.initial(request, *args, **kwargs)方法的源码
            def initial(self, request, *args, **kwargs):
                """
                Runs anything that needs to occur prior to calling the method handler.
                """
                self.format_kwarg = self.get_format_suffix(**kwargs)

                # Perform content negotiation and store the accepted info on the request
                neg = self.perform_content_negotiation(request)
                request.accepted_renderer, request.accepted_media_type = neg

                # Determine the API version, if versioning is in use.
                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是rest_framework中的Request的对象
        self.perform_authentication(request)   ##它是进行登陆验证的
        self.check_permissions(request)        ##它是就行权限验证的
        self.check_throttles(request)          ##它是进行频率验证的



        ############
        好了,继续下面的代码:
        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)
        ############
        ##注意啊,这里的request是rest_framework中的Request的对象
        ##很简单的if判断逻辑的代码,我说说大概意思吧,
        request.method.lower()   ---->>  本次请求方法的小写(get,post,put等等)
        self.http_method_names   ---->>  这里的self就是视图类对象,http_method_names就是一个列表,装着请求方法的小写
                                         这是很基本的面向对象的属性查找,自己看查找看看,看看在哪个类里?
        handler = getattr(self,A,B)  ---->>   面向对象里的反射,如果在self中有A的话,那么handler就是A的内存地址,没有的话就是B的内存地址
        response = handler(request, *args, **kwargs)   --->>  最终会执行上面得到的函数内存地址,将返回值赋值给response

        这里就举个例子,更加明白上面这几句代码。
        浏览器发送一个login的get请求,那么request.method.lower()就是get,它在http_method_names这个列表里面,所以handler就是get方法的
        内存地址(这里的get就是视图类里写的get方法),便会执行get这个方法,假如这个get方法的返回值是HttpResponse('login get'),
        那么response就是HttpResponse('login get')。



        再写一个注意的地方,回到dispatch这个方法,里面是不是有一个try....except捕捉异常的代码,它有什么用呢?这个跟进行登陆验证,权限验证,
        频率验证那里有关系。后面写这个的时候,我会再写。



    这部分就到此结束吧, 登陆验证,权限验证,频率验证 后面再写。
    不能密密麻麻写一大推,然后会发生太长不看(我就是这样哈哈)
    格式可能太差了,没办法,想到哪里写到哪里

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Python中__call__的用法

下一篇:手势识别中一些错误解决方法