django-CBV模式源码精读

django-CBV模式源码精读,第1张

django-CBV模式源码精读 0. django视图有两种写法,一般我们用FBV,今天我们揭开CBV的面纱 总结:


        # 1. 你在路由中写一个as_view,他实际上会自动执行,并返回一个内层函数地址,
        # 2. 等请求来了,django自动加括号执行View方法,并且把当前的request传入
        # 3. 然后实例化一个当前类对象,在进行一些判断,
        # 4. 给他封装一下属性-->判断结束执行dispatch,返回一个handler方法,
        # 5. handler方法,只有两种情况:1.你的get视图/post视图...
        #                                                      2. 报错信息
        # 6. 最终在封装一些属性,然后把view返回

一. 导入并写一个简单的url&视图
  # 提前说一下,django的路由规定,路由的第二个参数必须放一个函数的内存地址,或者一个include
    # as_view()执行完以后肯定返回一个内存地址
    path('text_view/', views.TextView.as_view()),
from django.views import View


class TextView(View):
    """cbv"""

    def get(self, request):
        return HttpResponse('ok')
二. 按住ctrl键,鼠标点as_view,点进去 三. 源码分析(他的精髓我基本上都有注释) 1. classonlymethod注释
@classonlymethod
    # 1. classonlymethod 只是继承了classmethod,本质上还是classmethod,只是比classmethod多了一点功能
    # 2. classmethod-->类的绑定方法,类调用的时候,会把当前类,作为第一个参数传进去
 2. as_view--->setup注释
@classonlymethod
    # 1. classonlymethod 只是继承了classmethod,本质上还是classmethod,只是比classmethod多了一点功能
    # 2. classmethod-->类的绑定方法,类调用的时候,会把当前类,作为第一个参数传进去
    def as_view(cls, **initkwargs):
        # 1. initkwargs--->一个普通的形参,只是名字好看一点,把它当成**kwargs即可
        """Main entry point for a request-response process."""
        for key in initkwargs:
            # 1. 这一步循环取值并判断,其实对我们来讲意义不大,只要知道,as_view()支持以字典的形式传参,例如:as_view({'get':'xxx'})
            # 2. 如果该形参有值,进行循环取值,并判断,如果传的值在http_method_names列表中的话,抛异常
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            # 1. 进行判断,比if高级了一点,判断当前传入的值,如果不在当前类中(当前类没有,去其父类,也就是,我们继承的View中找),抛异常
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            # 1. 利用闭包的思想(闭包的最基本的概念:在函数内部定义的变量对外部有调用)
            # 2. 提前说一下,as_view最终返回一个view的内存地址,
            # 3. 我们一开始就说了,django路由规定,路由的第二个参数必须放一个函数的内存地址/include,这个符合django的路由规定
            # 4. 绕了一圈,我们知道,原来as_view(),加括号执行后,居然返回一个内层函数view,并且as_view支持以字典的方式传参
            self = cls(**initkwargs)
            # 1. cls-->由于as_view是一个类的绑定方法,类调用的时候,会把类传进来,
            # 2. 那么cls就是我们当前调用的类--->TextView
            # 3. 他这一步就是把我们的TextView类加括号,实例化成对象(我们下列用TV对象代替他)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                # 1. 判断get是TV对象对象的方法
                # 2. head不是TV对象对象的方法
                self.head = self.get
                # 如果成立给TV对象增加一个实例属性,{'head':'get'}
            self.setup(request, *args, **kwargs)
            # 1. 调用TV对象的setup方法(TV对象中没有,去View中去找)
3.  setup方法的注释
self.setup(request, *args, **kwargs)
            # 1. 调用TV对象的setup方法(TV对象中没有,去View中去找)
    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        # self-->依旧是TV对象,兄弟们千万别迷了
        # 以下 *** 作,就是给TV对象添加实例化属性{'request':request,'args':args,'kwargs':kwargs}
        # 只是放在一个方法中写了
        # 这里粗略介绍一下函数跟方法的区别
        # 函数,所有参数手动传
        # 方法,第一个参数自动把当前调用者传进来
        self.request = request
        self.args = args
        self.kwargs = kwargs
4. as_view--->setup注释--->dispatch注释(精髓)
 self.setup(request, *args, **kwargs)
            # 1. 调用TV对象的setup方法(TV对象中没有,去View中去找)
            if not hasattr(self, 'request'):
                # 1. 老套路,判断request是否是TV对象的属性
                # 2. 不是抛异常
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            # 1. 是的话,执行dispatch方法,
            # 2. 说一下执行流程,首先去对象里面找(没有)--在去类中找(没有)--在去其父类中找(没有)--父类的父类,一直找到根(还没有报错,xxx没有这个属性)
            # 最终返回 handler方法
            # 3. handler-->存的是你在视图中写的 get/post...
            # 4. 或者是 异常方法
            return self.dispatch(request, *args, **kwargs)
    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            # 1. 把request.method-->GET/POST...,变成小写,判断是否在列表中
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            # 2. 反射,从TV对象中找到该方法,如果找不到,执行self.http_method_not_allowed
        else:
            handler = self.http_method_not_allowed
            # 3. 最后返回handler
            # 4. handler-->存的是你在视图中写的 get/post...
            # 5. 或者是 异常方法
        return handler(request, *args, **kwargs)

    def http_method_not_allowed(self, request, *args, **kwargs):
        # 记录日志,抛异常
        logger.warning(
            'Method Not Allowed (%s): %s', request.method, request.path,
            extra={'status_code': 405, 'request': request}
        )
        return HttpResponseNotAllowed(self._allowed_methods())
5. 最后
# 1. 是的话,执行dispatch方法,
            # 2. 说一下执行流程,首先去对象里面找(没有)--在去类中找(没有)--在去其父类中找(没有)--父类的父类,一直找到根(还没有报错,xxx没有这个属性)
            # 最终返回 handler方法
            # 3. handler-->存的是你在视图中写的 get/post...
            # 4. 或者是 异常方法
            return self.dispatch(request, *args, **kwargs)

        view.view_class = cls
        view.view_initkwargs = initkwargs
        # 1. 执行完,我大概说一下,这个view.view_class = cls是什么意思
        # 2. view是函数的名称,因为一切皆对象的原因,函数也是一个对象,
        # 3. 如果是对象,对象就支持 句点符 设值
        # 4. 这个就是给view添加两个属性

        # take name and docstring from class
        update_wrapper(view, cls, updated=())
        # 1. 对我们来讲愿意不大,
        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        # 1. 对我们来讲愿意不大,
        # 1. 最终返回view,到此CBV的精髓全部介绍完毕
        # 2. 在总结一下:
        # 你在路由中写一个as_view,他实际上会自动执行,并返回一个内层函数地址,
        # 等请求来了,django自动加括号执行View方法,并且把当前的request传入
        # 然后实例化一个当前类对象,在进行一些判断,
        # 给他封装一下属性-->判断结束执行dispatch,返回一个handler方法,
        # handler方法,只有两种情况:1.你的get视图/post视图...
        #                            2. 报错信息
        # 最终在封装一些属性,然后把view返回
        return view

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5720949.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存