django_CBV理解

路由如下,同时视图文件下存在class AuthView继承于 django.views.View:

urlpatterns = [
    path('api/v1/auth/', views.AuthView.as_view()),
]


然后查看对应Views.py文件中,发现并没有定义as_view()这个方法,所以一定是父类View中的方法
查看as_view源码,先只贴如下部分

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

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        #一般我们没有对as_view()传递任何参数,相当于initkwargs={},所以这个循环就直接跳过了
        for key in initkwargs:
            #如果as_view()传递了参数过来,但是字典的key是属于http_method_names中的一个,比如get=''、post=''......报如下错误
            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__))
            #如果传递过来的参数,比如传递views.AuthView.as_view(name='kobe'),但是在AuthView这个类中没有name这个属性,就会报错如下
            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):
            #这里的self=传递进来的类的实例化  即 自定义的这个AuthView类的实例化
            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__
                )
            #然后经过这些操作之后,返回dispatch方法,如果在views.py中的AuthView中我们自己重写了dispatch方法,就执行重写的,否则执行父类也就是现在这个类中的该方法
            return self.dispatch(request, *args, **kwargs)
        #给View函数添加属性,这在django中很常见,就好比声明一个函数fun1,里面不带任何东西,然后声明一个类A,可以直接把A绑定到函数里面去fun1.fun1_class=A
        #这里绑定的是cls,就是这个类AuthView
        view.view_class = cls
        #如果as_view()有传递参数过来,同时绑定参数
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        #update_wrapper(A,B)把B的相关属性赋值给A,当想要装饰某一个函数,但是又想要保持函数本身的属性的时候用到update_wrapper
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        #经过一系列加工之后,返回view
        return view
        
    def dispatch(self, request, *args, **kwargs):
        # 这里的self,指的是自定义的CBV类实例化得到的对象(AuthView)
        #在dispatch方法中,把request.method转换为小写再判断是否在定义的http_method_names中,如果request.method存在于http_method_names中,则使用getattr反射的方式来得到handler
        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)

执行步骤:

1.类名去调用as_view方法

2.as_view返回一个view方法名

3.urls执行view方法

4.执行到view方法self = cls(**initkwargs)#实例化一个对象cls对应的就是 自己写的那个视图类

5. 继续往下执行return self.dispatch(request, *args, **kwargs)#这时self是自己写的视图类的实例化对象 去该类中去寻找dispatch方法

6.LoginView视图类没有找到去对应的父类View去寻找

dispatch方法

7.找到http_method_names对应属性里面有各类方法

8.请求的方法名在这个属性中继续往下执行反射

9.利用反射去寻找对应的方法

#注意

getattr 第二个参数找不到就执行第三个参数 执行第三个方法直接报错返回 日志打印405

原文地址:https://www.cnblogs.com/alantammm/p/13937126.html