Django中CBV及其源码解释

FBV(function base views) 就是在视图里使用函数处理请求。

 

CBV(class base views) 就是在视图里使用类处理请求。

Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:

  1. 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
  2. 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性

CBV源码解析:

首先,在urls中,我们会有这样一个访问函数:

path('login/',views.LoginView.as_view() )

  当访问login时,django会调用  views.LoginView.as_view() 中 as_view() 这个函数,那么必须先要去看看LoginView中该函数构成:

class LoginView(View):
    def get(self,request):

        return render(request,"login.html")
    def post(self,request):

        return HttpResponse("Hello")

  LoginView 是我们在视图中创建的类,继承View,LoginView 没有as_view这个方法,于是我们来到继承的父类View,并找到as_view

 

 1  @classonlymethod
 2     def as_view(cls, **initkwargs):
 3         """Main entry point for a request-response process."""
 4         for key in initkwargs:
 5             if key in cls.http_method_names:
 6                 raise TypeError("You tried to pass in the %s method name as a "
 7                                 "keyword argument to %s(). Don't do that."
 8                                 % (key, cls.__name__))
 9             if not hasattr(cls, key):
10                 raise TypeError("%s() received an invalid keyword %r. as_view "
11                                 "only accepts arguments that are already "
12                                 "attributes of the class." % (cls.__name__, key))
13 
14         def view(request, *args, **kwargs):
15             self = cls(**initkwargs)
16             if hasattr(self, 'get') and not hasattr(self, 'head'):
17                 self.head = self.get
18             self.request = request
19             self.args = args
20             self.kwargs = kwargs
21             return self.dispatch(request, *args, **kwargs)
22         view.view_class = cls
23         view.view_initkwargs = initkwargs
24 
25         # take name and docstring from class
26         update_wrapper(view, cls, updated=())
27 
28         # and possible attributes set by decorators
29         # like csrf_exempt from dispatch
30         update_wrapper(view, cls.dispatch, assigned=())
31         return view

从源码中可以看到as_view最后返回了一个view

 此时

path('login/',views.LoginView.as_view() )    ------->>>>   path('login/',View.view ) 


当有用户登录Login页面时,dajango会自动调用 View.view

又找到view的方法,源码如下:
1  def view(request, *args, **kwargs):
2             self = cls(**initkwargs)
3             if hasattr(self, 'get') and not hasattr(self, 'head'):
4                 self.head = self.get
5             self.request = request
6             self.args = args
7             self.kwargs = kwargs
8             return self.dispatch(request, *args, **kwargs)
解读一下view方法:
self = cls(**initkwargs)  cls为调用as_view时传入的类,为调用该类的对象 LoginView ,这里self为 LoginView 的实例对象.
return self.dispatch(request, *args, **kwargs)  最后返回的时候,先调用了self.dispatch(request, *args, **kwargs)这个方法.而cls就是LoginView ,一步步找到
dispatch这个方法

dispatch源码(分发):
1     def dispatch(self, request, *args, **kwargs):
2         # Try to dispatch to the right method; if a method doesn't exist,
3         # defer to the error handler. Also defer to the error handler if the
4         # request method isn't on the approved list.
5         if request.method.lower() in self.http_method_names:
6             handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
7         else:
8             handler = self.http_method_not_allowed
9         return handler(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
   handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
其中
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
获取反射获取到对应的方法('get', 'post', 'put'....)
最后返回:handler(request, *args, **kwargs) 的调用结果,完成分发
 self.http_method_not_allowed 为错误或找不到值时报错调用的方法

 

 更多可以查看



 

posted @ 2019-03-04 20:56  Mixtea  阅读(280)  评论(0编辑  收藏  举报