ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

django的View和drf的APIView源码解析

2020-07-06 20:38:59  阅读:321  来源: 互联网

标签:APIView self args request dispatch django 源码 kwargs view


目录

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对象进行封装,添加了根据请求来源返回不同结果的功能

标签:APIView,self,args,request,dispatch,django,源码,kwargs,view
来源: https://www.cnblogs.com/achai222/p/13257321.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有