zoukankan      html  css  js  c++  java
  • django的View和drf的APIView源码解析

    django中的View源码解析

    FBV:    path('admin/', admin.site.urls),
    CBV:    path('books/', views.BookView.as_view()),
    

    在路由层使用CBV时需要执行 CBV.as_view()方法,使该位置的实参变为一个FBV(函数地址)

    as_view方法的返回值是view

    view是一个函数,即CBV的views.BookView.as_view()的结果就是views.BookView.view

    在收到请求,路由匹配成功之后会触发view函数的运行

    view函数 执行了self.dispatch(request, *args, **kwargs)并返回该函数的返回值

    class View:
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.setup(request, *args, **kwargs)
                if not hasattr(self, 'request'):
                    raise AttributeError(
                        "%s instance has no 'request' attribute. Did you override "
                        "setup() and forget to call super()?" % cls.__name__
                    )
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    

    进入dispatch方法查看源码

        def dispatch(self, request, *args, **kwargs):
            # Try to dispatch to the right method; if a method doesn't exist,
            # defer to the error handler. Also defer to the error handler if the
            # request method isn't on the approved list.
            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
            return handler(request, *args, **kwargs)
    

    dispatch中对请求方式是否在http_method_names列表中进行了判断

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    

    如果请求方式在这个列表中则进行反射,从我们自定义的CBV中取出与请求方式同名的函数执行,

    如果CBV中没该名字的函数或者请求方式不在该列表中,就会报错,拒绝访问

    drf中APIView源码解析

    FBV:    path('admin/', admin.site.urls),
    CBV:    path('books/', views.BookAPIView.as_view()),
    

    在路由层使用CBV时需要执行 CBV.as_view()方法,使该位置的实参变为一个FBV(函数地址)

    看源码可知执行该方法得到的返回值为csrf_exempt(view)

    装饰器的语法糖的原理就是view=csrf_exempt(view),

    所以返回csrf_exempt(view)也可以看作是 为view添加了一个csrf_exempt装饰器

    `

    APIView继承了django中的View类

    class APIView(View):
        @classmethod
        def as_view(cls, **initkwargs):
            view = super().as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
            return csrf_exempt(view)
    

    在执行APIView的as_view方法时调用了父类的as_view方法,也就是View的as_view方法

    class View:
    	@classonlymethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.setup(request, *args, **kwargs)
                if not hasattr(self, 'request'):
                    raise AttributeError(
                        "%s instance has no 'request' attribute. Did you override "
                        "setup() and forget to call super()?" % cls.__name__
                    )
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    

    View的as_view方法执行并返回了self.dispatch(request, *args, **kwargs)

    注意:这里的self指代的是自己写的CBV的对象

    所以self.dispatch(request, *args, **kwargs)触发的不是View中的dispatch方法

    按照名称空间的属性查找可以知道,它是先从自己写的CBV的对象中查看是否有dispatch方法

    如果没有则执行父类,也就是APIView中的dispatch方法

    class APIView(View):
        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
    

    APIView中的dispatch方法基本的功能和View中的dispatch方法一致,但是添加了一些别的功能:

    1. request的封装
      
      request = self.initialize_request(request, *args, **kwargs)
      self.request = request
      

    对request进行了封装:将原生django中的request传入initialize_request方法,通过实例化drf定义的Request类,产生了一个新的request对象,进行替换,在原本的request对象的功能基础上,额外添加了一些功能,例如request.data属性

    1. 异常处理
      
      except Exception as exc:
              response = self.handle_exception(exc)
      

    对异常进行捕获,使我们可以重写handle_exception方法,返回json格式的数据

    1. response的封装
      
              self.response = self.finalize_response(request, response, *args, **kwargs)
              return self.response
      

    对response对象进行封装,添加了根据请求来源返回不同结果的功能

  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/achai222/p/13257321.html
Copyright © 2011-2022 走看看