Django之CBV的使用 ---- 第10章

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">&times;</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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章