• Django之CBV中View、APIView源码分析


    View源码分析:

    views文件:

    class MyView(View):
        def get(self,request):
            return HttpResponse('ok')
        def post(self,request):
            return HttpResponse('post')

    urls文件:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$',views.MyView.as_view()),
    ]

    View源码思路分析(这里拿重要的部分源码进行分析):

    '''
    主要思路:View--》as_view --》as_view下的函数
    当有路由匹配进来的时候,就会执行as_view这个方法
    '''
    
    class View(object):
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']  
        #继承classmethod
        @classonlymethod
        '''
          这时会把我们在vies创建的MyView类,当作参数传递给as_view这个方法。
          相当于as_view(MyView)
          **initkwargs是url匹配传递过来的参数:例如 url(r'^$',views.MyView.as_view(age=1)),
        '''
        def as_view(cls, **initkwargs):
            """
            Main entry point for a request-response process.
            """
    
            def view(request, *args, **kwargs):
                '''
                self = cls(**initkwargs)
                这一步是实例化一个对象,将我们传进来的类实例化赋值给self
                相当于self=MyView(参数)
                '''
                self = cls(**initkwargs)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request  #将当前的request请求赋值给对象中的request.
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
            return view
    
        def dispatch(self, request, *args, **kwargs):
            # request: 还是当前的请求对象
            if request.method.lower() in self.http_method_names:
                '''
                获取当前对象(MyView类的对象)的方法的内存地址
                例如get请求:handler=getattr(self,'get')
                '''
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            return handler(request, *args, **kwargs) #相当于执行get(request)

    APIView源码分析:

     views文件:

    from rest_framework.views import APIView
    class MyAPIView(APIView):
        def get(self,request):
            #此时的request是drf重新封装后的request
            print(request._request)  #原生request
            # 相当于request.GET
            data=request.query_params  
            return HttpResponse('ok')
        def post(self,request):
            # 相当于request.POST
            post_data=request.data
            file_data=request.FILES

    urls文件

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'apiview/',views.MyAPIView.as_view())
    ]

    APIView源码分析:

    '''
    #请求来了-》路由匹配上-》view(request)-》调用了self.dispatch(),这时执行的是apiview的dispatch,而不是view的dispatch
    '''
    class APIView(View):
    
        @classmethod
        def as_view(cls, **initkwargs):
            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().as_view(**initkwargs)
            此时的view就View源码的as_view方法下的view
            即调用父类(view)的as_view方法。
            此时调用的dispatch方法是APIView的dispatch方法,而不是View的
            执行顺序是从当前类(MyAPIView)中查找,找不到再从父类(APIView)中查找,再找不到再从APIView的父类View中找
            '''
            view = super().as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
    
            #只要继承了APIView,就不会再进行csrf认证
            return csrf_exempt(view)
    
        #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是当前请求的request
                左边的request是重新封装后的request
                具体可以参照源码4
            '''
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                #三大认证模块(具体看下面源码5)
                self.initial(request, *args, **kwargs)
                # 这部分跟View类中那部分一样。
                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
    
    
        #源码4、重新封装request的方法
        def initialize_request(self, request, *args, **kwargs):
            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
            )
    #源码5 APIView的initial方法 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 ''' 认证组件:校验用户 - 游客、合法用户、非法用户 游客:代表校验通过,直接进入下一步校验(权限校验) 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验) 非法用户:代表校验失败,抛出异常,返回403权限异常结果 ''' self.perform_authentication(request) ''' 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色 认证通过:可以进入下一步校验(频率认证) 认证失败:抛出异常,返回403权限异常结果 ''' self.check_permissions(request) ''' 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s) 没有达到限次:正常访问接口 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问 ''' self.check_throttles(request)

     

  • 相关阅读:
    MCU软件最佳实践——独立按键
    MCU软件最佳实践——矩阵键盘驱动
    MCU软件最佳实践——使用printf打印数据
    CAP定理图解证明
    类型和变量
    数字ID过长 精度丢失 (已解决:后端方案)
    Springboot 异步线程池配置(小型应用)
    Java 数字 字符串 简单操作
    Java 网络请求
    Java 时间 日 周 月 季 年
  • 原文地址:https://www.cnblogs.com/nq31/p/13904695.html
Copyright © 2020-2023  润新知