The source code parsing of Django CBV mode
In general, the nature of HTTP requests is based on the socket
Django view functions can be based on the FBV mode, or can be based on the CBV mode.
The FBV-based pattern is the association of URL and view functions in the Django Routing map table, while the CBV-based pattern defines the view class in the views.py file, view functions in the view class, such as Get,post,put,delete, etc.
Create a new project with Django and create a route map
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [ url(r'^cbv/$',views.CBV.as_view())]
The corresponding views.py file contents:
from django.shortcuts import render,HttpResponsefrom django.views import Viewclass CBV(View): def get(self,request): return HttpResponse("GET") def post(self,request): return HttpResponse("POST")
Launch the project, using the browser request URL http://127.0.0.1:8000/cbv/
, the browser displays the result as:
When a request arrives, Django executes the method in the Django middleware and then performs a routing match.
After the route match is complete, the As_view method in the CBV class is executed.
CBV does not define the as_view
method, because CBV继承自Django的View
, so会执行Django的View类中的as_view方法
Some source code for the As_view method of the Django view class
Class View (object): "" "intentionally simple the parent class for any views. Only implements Dispatch-by-method and simple sanity checking. "" "Http_method_names = [' Get ', ' post ', ' Put ', ' Patch ', ' delete ', ' head ', ' Options ', ' Trace '] def __init__ (self, **k Wargs): "" "Constructor. called in the URLconf; can contain helpful extra keyword arguments, and other things. "" "# Go through keyword arguments, and either save their values to We # instance, or raise an error. For key, value in Six.iteritems (Kwargs): SetAttr (self, key, value) @classonlymethod def as_view (CLS, * *initkwargs): "" "Main entry point for a request-response process. "" "for key in Initkwargs: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__)) if not hasattr (CLS, key): Raise TypeError ('%s () received an invalid key Word%r. As_view "" Only accepts arguments that is already " "Attributes of the class"% (cls.__name__, key)) def view (Request, *args, **kwargs): Self = CLS (**ini Tkwargs) if hasattr (self, ' get ') and not hasattr (self, ' head '): Self.head = Self.get Self.request = Request Self.args = args Self.kwargs = Kwargs return Self.dispatch (Request , *args, **kwargs) View.view_class = cls View.view_initkwargs = Initkwargs # take name and docstring From class Update_wrapper (view, CLS, updated= ()) # and possible attributes set by decorators # like C Srf_exempt from Dispatch update_wrapper (view, Cls.dispatch, assigned= ()) return view
From the view source can be seen, in the view class, the first definition of the HTTP request eight ways
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
In the as_view方法
judgment, if the requested method is not in http_method_names
, an exception is thrown,这里的cls实际上指的是自定义的CBV类
The view method is then defined in the As_view method to instantiate the CBV class in the View method, get the Self object, and then encapsulate the request requests sent by the browser in the Self object
self = cls(**initkwargs)
Finally, the dispatch method in the Self object is called and the value of the dispatch method is returned to process the request
At this time由于self对象就是CBV实例化得到,所以会先执行自定义的CBV类中的dispatch方法。如果CBV类中没有定义dispatch方法则执行Django的View中的dispatch方法
The dispatch method source in Django View
class View(object): """ 中间省略 """ 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. 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)
In the dispatch method, convert the Request.method to lowercase to determine if Request.method is present in Http_method_names if it is in the defined http_method_names. The getattr reflex is used to get the handler
In the dispatch method here, self refers to the object that is instantiated by the custom CBV class
Get the Request.method corresponding method from the CBV class, then execute the method in CBV and return
From this, you can know如果在Django项目中使用CBV的模式,实际上调用了getattr的方式来执行获取类中的请求方法对应的函数
Conclusion:
CBV基于反射实现根据请求方式不同,执行不同的方法
Customizing the Dispatch method
If you want to perform some action when requesting a URL in a project that is based on CBV mode, you can define the dispatch method in the class that corresponds to the URL
Modify the views.py file
class CBV(View): def dispatch(self, request, *args, **kwargs): func = getattr(self,request.method.lower()) return func(request,*args,**kwargs) def get(self,request): return HttpResponse("GET") def post(self,request): return HttpResponse("POST")
You can also override the dispatch method with inheritance:
class CBV(View): def dispatch(self, request, *args, **kwargs): print("before") res = super(CBV, self).dispatch(request, *args, **kwargs) print("after") return res def get(self,request): return HttpResponse("GET") def post(self,request): return HttpResponse("POST")
To refresh the browser, the Django spooling results are as follows:
Browser page Results
Similarly, if there are multiple classes based on CBV, and there are multiple classes of shared functionality, to avoid duplication, you can define a class individually, override the dispatch method in this class, and then inherit the class from the view class that corresponds to the URL.
Modify the urls.py file
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [ url(r'^cbv1/$',views.CBV1.as_view()), url(r'^cbv2/$',views.CBV2.as_view()),]
views.py File Contents
from django.shortcuts import render,HttpResponsefrom django.views import Viewclass BaseView(object): def dispatch(self, request, *args, **kwargs): func = getattr(self, request.method.lower()) return func(request, *args, **kwargs)class CBV1(BaseView,View): def get(self,request): return HttpResponse("CBV1 GET") def post(self,request): return HttpResponse("CBV1 POST")class CBV2(BaseView,View): def get(self,request): return HttpResponse("CBV2 GET") def post(self,request): return HttpResponse("CBV2 POST")
Python-oriented objects let you know that when a request arrives at a view class, the dispatch methods in the CBV1 and CBV2 classes are executed first, but there is no CBV2 method in the CBV1 and dispatch classes, and the dispatch method is found in the parent class in order. The dispatch method in the Baseview class is executed at this point.
Browser request URL http://127.0.0.1:8000/cbv1/
, browser page display
Browser request URL http://127.0.0.1:8000/cbv2/
, browser page display