源碼解析Django CBV的本質

來源:互聯網
上載者:User
Django CBV模式的源碼解析

通常來說,http請求的本質就是基於Socket

Django的視圖函數,可以基於FBV模式,也可以基於CBV模式。

基於FBV的模式就是在Django的路由映射表裡進行url和視圖函數的關聯,而基於CBV的模式則是在views.py檔案中定義視圖類,在視圖類中視圖函數,如get,post,put,delete等

使用Django建立一個項目,建立一個路由映射

from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [    url(r'^cbv/$',views.CBV.as_view())]

對應的views.py檔案內容:

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")

啟動項目,使用瀏覽器請求URLhttp://127.0.0.1:8000/cbv/,瀏覽器顯示結果為:

請求到達Django會先執行Django中介軟體裡的方法,然後進行進行路由匹配。

在路由匹配完成後,會執行CBV類中的as_view方法。

CBV中並沒有定義as_view方法,由於CBV繼承自Django的View,所以會執行Django的View類中的as_view方法

Django的View類的as_view方法的部分源碼

class View(object):    """    Intentionally simple parent class for all views. Only implements    dispatch-by-method and simple sanity checking.    """    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']    def __init__(self, **kwargs):        """        Constructor. Called in the URLconf; can contain helpful extra        keyword arguments, and other things.        """        # Go through keyword arguments, and either save their values to our        # 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 keyword %r. as_view "                                "only accepts arguments that are already "                                "attributes of the class." % (cls.__name__, key))        def view(request, *args, **kwargs):            self = cls(**initkwargs)            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 csrf_exempt from dispatch        update_wrapper(view, cls.dispatch, assigned=())        return view

從View的源碼可以看出,在View類中,先定義了http請求的八種方法

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

as_view方法中進行判斷,如果請求的方法沒在http_method_names中,則會拋出異常,這裡的cls實際上指的是自訂的CBV類

接著as_view方法中又定義view方法,在view方法中對CBV類進行執行個體化,得到self對象,然後在self對象中封裝瀏覽器發送的request請求

self = cls(**initkwargs)

最後又調用了self對象中的dispatch方法並返回dispatch方法的值來對request進行處理

此時,由於self對象就是CBV執行個體化得到,所以會先執行自訂的CBV類中的dispatch方法。如果CBV類中沒有定義dispatch方法則執行Django的View中的dispatch方法

Django的View中的dispatch方法源碼

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)

在dispatch方法中,把request.method轉換為小寫再判斷是否在定義的http_method_names中,如果request.method存在於http_method_names中,則使用getattr反射的方式來得到handler

在這裡的dispatch方法中,self指的是自訂的CBV類執行個體化得到的對象

從CBV類中擷取request.method對應的方法,再執行CBV中的方法並返回

由此,可以知道如果在Django項目中使用CBV的模式,實際上調用了getattr的方式來執行擷取類中的要求方法對應的函數

結論:

CBV基於反射實現根據請求方式不同,執行不同的方法
自訂dispatch方法

如果想在基於CBV模式的項目中在請求某個url時執行一些操作,則可以在url對應的類中定義dispatch方法

修改views.py檔案

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")

也可以使用繼承的方式重寫dispatch方法:

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")

重新整理瀏覽器,Django後台列印結果如下:

瀏覽器頁面結果

同理,如果有基於CBV的多個類,並且有多個類共用的功能,為了避免重複,可以單獨定義一個類,在這個類中重寫dispatch方法,然後讓url對應的視圖類繼承這個類

修改urls.py檔案

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檔案內容

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的物件導向可以知道,請求到達視圖類時,會先執行CBV1和CBV2類中的dispatch方法,然而CBV1和CBV2類中並沒有dispatch方法,則會按照順序在父類中尋找dispatch方法,此時就會執行BaseView類中的dispatch方法了

用瀏覽器請求urlhttp://127.0.0.1:8000/cbv1/,瀏覽器頁面顯示

用瀏覽器請求urlhttp://127.0.0.1:8000/cbv2/,瀏覽器頁面顯示

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.