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