1. CBV的引入
FBV 即 Function-Based-View,是 通過函數來處理請求
。CBV 即 Class-Based-View,是 通過類來處理請求
。相對於傳統的FBV方式,CBV的優點體現在:① 提高了代碼的複用性,可以使用面嚮對象的技術,比如Mixin(多繼承);② 可以用不同的函數針對不同的HTTP方法處理,而不是通過很多if判斷,提高代碼可讀性。
2. CBV的應用
登錄功能的實現,定義一個Login類用於處理用戶的登錄請求。路由URL匹配成功後,開始匹配請求的方法method。如果是GET請求,執行Login類的get方法,獲取到登錄頁面。如果是POST請求,將登錄表單的數據發送到後臺驗證。無須使用if語句來判斷請求的方法是什麼:
urls.py
:
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('login.html/', views.Login.as_view()),
]
views.py
:
class Login(View):
"""
get:查詢
post:創建
put:更新
delete:刪除
"""
def get(self, request):
"""
請求的方法是get時執行
:param request:
:return:
"""
return render(request, 'login.html')
def post(self, request):
"""
請求的方法是post時執行
:param request:
:return:
"""
username = request.POST.get('username')
print(username)
return HttpResponse('登錄成功!')
login.html
:
...
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-danger">
<div class="panel-heading" style="font-weight: bold">用戶登錄
<button type="button" class="close" id="close_add_modal"><span aria-hidden="true">×</span>
</button>
</div>
<div class="panel-body">
<form method="post">
<div class="form-group">
<label for="">用戶名</label>
<input type="text" name="username" class="form-control" id="name" placeholder="請輸入用戶名"
autofocus>
</div>
<div class="form-group">
<label for="">密碼</label>
<input type="password" name="pwd" class="form-control" id="pwd" placeholder="請輸入密碼">
</div>
<input type="submit" class="btn" value="登錄" id="add_student" style="background: #f2dede;">
</form>
</div>
</div>
</div>
</div>
</div>
...
表單只支持POST和GET方式提交!AJAX支持所有的請求!
3. dispatch方法
請求的方法有很多,如果使用 if 來一一判斷就要寫很多判斷語句。但是,實際上使用的並不是條件判斷,而是 反射
。用戶發送請求,URL會匹配到類。找類中的方法時,使用getattr方法判斷請求的方法是否對應類中的方法
。查看源碼的時候發現在執行get和post方法之前,還執行了dispatch方法。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.
if request.method.lower() in self.http_method_names:
# 在當前對象中找用戶提交的方法request.method.lower(),handler就是找到的方法名
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# handler加括號就是執行這些方法
return handler(request, *args, **kwargs)
dispatch方法的功能類似 裝飾器
的功能,在執行請求的方法之前和之後做其它操作:
class Login(View):
def dispatch(self, request, *args, **kwargs):
print('Before')
obj = super(Login, self).dispatch(request, *args, **kwargs)
print('After')
return obj
def get(self, request):
print('get')
return render(request, 'login.html')
def post(self, request):
print('post')
return HttpResponse('登錄成功!')
執行記錄:
[06 / Jun / 2020 01: 32:33] "GET /login.html/ HTTP/1.1" 200 1813
Before
get
After
[06 / Jun / 2020 01: 32:38] "GET /login.html/ HTTP/1.1" 200 1813
[06 / Jun / 2020 01: 32:41] "POST /login.html/ HTTP/1.1" 200 15
Before
post
After
如果要對get和post等請求方法做批量操作時,沒必要在每個方法中都寫一遍,只要在dispatch寫一遍就可以了
。
4. CBV中添加裝飾器
CBV中添加裝飾器有兩種方法,分別是在指定的方法中添加裝飾器和在類上添加裝飾器。在方法中添加裝飾器:
views.py:
from django.views import View
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
def wrapper(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
class Login(View):
@method_decorator(csrf_protect)
def get(self, request):
pass
@method_decorator(wrapper)
def post(self, request):
pass
在類上添加裝飾器不可以直接把裝飾器放在類上,這樣時錯誤的,如:
from django.views import View
from django.views.decorators.csrf import csrf_protect
@csrf_protect
class Login(View):
def get(self, request):
pass
def post(self, request):
pass
在類上加裝飾器,需要用到 @method_decorator
:
from django.views import View
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
# 對類中所有的方法添加csrf_protect裝飾器
@method_decorator(csrf_protect)
class Login(View):
def get(self, request):
pass
def post(self, request):
pass
還可以通過類方法名稱來指定方法添加裝飾器:
from django.views import View
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect, name='get')
@method_decorator(csrf_protect, name='post')
class Login(View):
def get(self, request):
pass
def post(self, request):
pass
csrf的裝飾器在使用CBV的情況下不能加到類方法上!
以上兩種方法都具有爲所有的函數加裝飾器的功能,不過如果 想爲所有類方法添加裝飾器顯得比較麻煩!
這裏還有一種方法可以 爲所有的方法加上某個裝飾器
,那就是把裝飾器加到dispatch方法上:
from django.views import View
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
def wrapper(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(wrapper, name='dispatch')
class Login(View):
def get(self, request):
pass
def post(self, request):
pass