django的類視圖,CBV:
咱們在開始接觸django的時候,習慣於使用函數編寫視圖,即FBV。使用FBV時,咱們只須要在路由匹配時,對應的路由下找到這個函數就能夠了,這樣作看似很和諧,可是有的時候,譬如說,當咱們須要根據同一個url請求方法的不一樣而去執行不一樣的操做時,若是使用FBV去編寫視圖,那麼咱們就須要在視圖函數中不斷地去執行if request.method=='請求方法' 去判斷要去執行什麼內容,此時的代碼就顯得不是很優雅。可是此時若是咱們使用CBV的方式來編寫視圖,一樣的需求,代碼就會顯得優雅不少,下面就讓我來介紹一下CBV的具體實現:python
在django中使用CBV編寫視圖:
一、首先咱們自定義的視圖類須要繼承django.views.View類
二、在視圖類中定義以'請求方法名稱小'寫爲名稱的方法,這樣在執行不一樣的請求方法的時候就回去自動執行對應的函數
三、在路由映射的時候,要執行這個試圖類的as_view()方法,注意這個方法繼承自django.views.View數據庫
示例代碼以下:
'views.py'文件:
from django.views import View
from django.http import HttpResponsedjango
class UserInfoView(View):app
def get(self, request, *args, **kwargs):
return HttpResponse('get user')函數
def post(self, request, *args, **kwargs):
return HttpResponse('post user')源碼分析
def delete(self, request, *args, **kwargs):
return HttpResponse('delete user')post
'url.py'文件
from app import views
urlpatterns = [
path('user/', views.UserInfoView.as_view())
]atom
上述示例代碼就能夠根據同一個url執行不一樣的方法時去執行不一樣的操做url
CBV實現的源碼分析:
一、請求進來,路由找到試圖類並執行as_view方法,執行這個方法時其實會返回一個view函數,所以能夠看作請求進來以後會先執行試圖類的view方法,源碼以下:
@classonlymethod
def as_view(cls, **initkwargs):
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))spa
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
update_wrapper(view, cls, updated=())
update_wrapper(view, cls.dispatch, assigned=())
return view
二、從上面的源碼中能夠看出執行view方法,實際上就是返回self.dispatch方法,也就是說會去執行self.dispatch方法
三、由於試圖類自己沒有定義dispatch方法,那麼在執行dispatch方法的時候就須要去其父類裏面查找,而父類裏面的dispatch方法則會根據請求方法的不一樣基於python類的反射去找到相應的方法,而後執行,這樣就會自動實現根據請求方法的不一樣去執行不一樣的內容了,dispatch方法的源碼以下:
def dispatch(self, request, *args, **kwargs):
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)
CBV之添加裝飾器:
在咱們使用函數試圖FBV的時候,若是咱們想要給其加上一個裝飾器,直接加就能夠了,例如,在建立django項目的時候,默認全局使用csrf防禦,若是咱們想要在某個函數試圖上不使用CSRF保護,那麼咱們能夠給這個視圖函數直接添加一個裝飾器便可,示例代碼以下:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
return HttpResponse('index')
可是,當咱們想要給CBV添加裝飾器,那麼咱們須要作的就不是在其內部的方法上添加,若是和FBV同樣直接添加到方法上,那麼這不會起任何做用。在CBV上添加裝飾器的方法有兩種,第一種是重寫父類的dispatch方法,並將裝飾器添加到dispatch方法上,與此同時在CBV上添加裝飾器最好使用django.utils.decorators.method_decorator方法進行包裹。第二種方法則是直接添加在類上,只不過這時你須要使用django.utils.decorators.method_decorator來進行封裝。下面的例子是咱們在django中針對重要的數據操做,想要實現數據庫的事件特性而添加的裝飾器:
一、方法一:
from django.utils.decorators import method_decorator
from django.db import transaction
class OrderView(View):
@method_decorator(transaction.atomic)
def dispatch(self, request, *args, **kwargs):
return super(OrderView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def patch(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass
二、方法二:
from django.utils.decorators import method_decorator
from django.db import transaction
@method_decorator(transaction.atomic, name='dispatch')
class OrderView(View):
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def patch(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass