# 1. 你在路由中写一个as_view,他实际上会自动执行,并返回一个内层函数地址,
# 2. 等请求来了,django自动加括号执行View方法,并且把当前的request传入
# 3. 然后实例化一个当前类对象,在进行一些判断,
# 4. 给他封装一下属性-->判断结束执行dispatch,返回一个handler方法,
# 5. handler方法,只有两种情况:1.你的get视图/post视图...
# 2. 报错信息
# 6. 最终在封装一些属性,然后把view返回
# 提前说一下,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 = kwargs4. 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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)