django中CBV视图模式的View源码分析
位置:
1.找到自己项目用的解释器存储位置
H:pythonProjectLibsite-packagesdjangoviewsgenericase.py
在base.py里有一个View类
2.也可以通过from django.views import View 按住ctrl点击View会直接跳到该类的位置
CBV形式的路由
path(r"^login/",views.MyLogin.as_view())
CBV形式的视图函数
from django.views import View
class MyLogin(View):
def get(self,request): #get请求时执行的函数
return render(request,"form.html")
def post(self,request): #post请求时执行的函数
return HttpResponse("post方法")
CBV源码分析:
当上述的login请求来了之后—》会执行后面的views.MyLogin.as_view()—》这个地方应该放的是函数的内存地址,views.MyLogin.as_view()执行完,是个函数内存地址,—views.MyLogin.as_view()会去views.py中找到MyLogin这个类,然后找as_view()方法,发现没有–》去其父类中找就是View类中找—》执行as_view()方法最终返回的是一个View类内部的一个view函数内存地址—》然后django框架会自动给view这个函数加括号调用,再传入request这个参数—>而view这个内部函数返回的是return handler(request, *args, **kwargs)就是对应类中get或者post方法
as_view()方法分析:
@classonlymethod # 1.这个as_view是一个类方法,所以用类调用时,会自动把调用的类传入给这个函数的cls
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
# 2.因为url那边没有传参,所以initkwargs为空,先忽略该层代码
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(
"The method name %s is not accepted as a keyword argument "
"to %s()." % (key, cls.__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)
)
# 3.执行该view函数
def view(request, *args, **kwargs): # request是当次请求的数据
# 5.cls是当前调用的类MyLogin,cls加括号产生对象给了self,这里现在self就是类MyLogin产生的对象
self = cls(**initkwargs)
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__
)
# 6.view函数返回了self.dispatch(request, *args, **kwargs)方法,
# self本身没有dispatch方法,就去MyLogin中找,MyLogin没有就去View类中找,找到了
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# __name__ and __qualname__ are intentionally left unchanged as
# view_class should be used to robustly determine the name of the view
# instead.
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.__annotations__ = cls.dispatch.__annotations__
# Copy possible attributes set by decorators, e.g. @csrf_exempt, from
# the dispatch method.
view.__dict__.update(cls.dispatch.__dict__)
# Mark the callback if the view class is async.
if cls.view_is_async:
view._is_coroutine = asyncio.coroutines._is_coroutine
# 4.as_view返回的是该函数内部的view函数内存地址,所以具体读下view函数就行
return view
上述as_view()方法返回了一个dispatch方法,dispatch方法分析:
# 1.dispatch将MyLogin这个类产生的对象self和request请求对象传入了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.
# 2.判断request.method方法在不在http_method_names里,ttp_method_names对象里没有最后去View类里找到了
if request.method.lower() in self.http_method_names:
# 3.通过getattr方法反射,self.http_method_not_allowed这个就当没有前面的方法时的一个默认值
# handler最后得到的就是MyLogin中定义的get或者post方法的内存地址
handler = getattr(
self, request.method.lower(), self.http_method_not_allowed
)
else:
handler = self.http_method_not_allowed
# 4.最后这个方法将handler加括号,再传入request参数调用的结果返回出去==执行了MyLogin的get或者post方法
return handler(request, *args, **kwargs)