django視圖 CBV 和 FBV
- 2019 年 10 月 8 日
- 筆記
目錄
視圖 CBV 和 FBV
什麼是視圖?
一個視圖函數(類),簡稱視圖,是一個簡單的Python 函數(類),它接受Web請求並且返回Web響應。 響應可以是一張網頁的HTML內容,一個重定向,一個404錯誤,一個XML文檔,或者一張圖片。放置在項目 (project)或應用程序(app)目錄中的名為views.py的文件中。
- 下面是一個以HTML文檔的形式返回當前日期和時間的視圖:
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
- 讓我們來逐行解釋下上面的代碼:
首先,我們從 django.http模塊導入了HttpResponse類,以及Python的datetime庫。 接着,我們定義了current_datetime函數。它就是視圖函數。每個視圖函數都使用HttpRequest對象作為第一個參數, 並且通常稱之為request。 注意,視圖函數的名稱並不重要;不需要用一個統一的命名方式來命名,以便讓Django識別它。 我們將其命名為current_datetime,是因為這個名稱能夠比較準確地反映出它實現的功能。 這個視圖會返回一個HttpResponse對象,其中包含生成的響應。每個視圖函數都負責返回一個HttpResponse對象。 Django使用請求和響應對象來通過系統傳遞狀態。 當瀏覽器向服務端請求一個頁面時,Django創建一個HttpRequest對象,該對象包含關於請求的元數據。然後, Django加載相應的視圖,將這個HttpRequest對象作為第一個參數傳遞給視圖函數。 每個視圖負責返回一個HttpResponse對象。
FBV function based view 基於函數的視圖
from app01 import models from django.shortcuts import render, redirect, HttpResponse import datetime def mul(request): now = datetime.datetime.now() return render(request, 'mul.html',{'now':now})
- 使用 FBV
#urls.py 文件 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^mul', views.mul), ]
CBV class based view 基於類的視圖
from app01 import models from django.views import View from django.shortcuts import render, redirect, HttpResponse class AddPublisher(View): def get(self,request): """處理get請求""" return response def post(self,request): """處理post請求""" return response #處理求響的邏輯很清晰
- 使用CBV:
#urls.py 文件 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^add_publisher/', views.AddPublisher.as_view()), ]#固定寫法注意.as_view()是要加括號的
小技巧
我們寫的視圖,可以接收,處理8種請求,頁面發來的8種請求: from app01 import views #ctrl+鼠標右擊views 查看源碼 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'] #可以看到views 默認接收了八種請求'get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace' #那我在寫視圖函數是可以重新定義http_method_names = ['get',post]讓這個視圖,讓它只接收get和post請求
- 在CBV 視圖中request和self.request效果是一樣的

CBV 如何獲取頁面請求類型,並響應的
1. 項目啟動,執行AddPublisher.as_view() ——》 view url(r'add_publisher/',views.AddPublisher.as_view()) url(r'add_publisher/', view ) 2. 請求到來時執行view函數: 1. 實例化AddPublisher ——》 self 2. self.request = reqeust 3. 執行self.dispatch(request,*args,**kwargs) 1. 判斷請求方式是否被允許 http_method_names = [] 1. 允許 通過反射獲取到當前請求方式對應的方法 ——》 handler 2. 不允許 self.http_method_not_allowed ——》 handler 2. 執行handler(request,*args,**kwargs) ——》 返迴響應
使用裝飾器的 FBV
- FBV本身就是一個函數,所以和給普通的函數加裝飾器無差:
def wrapper(func): def inner(*args, **kwargs): start_time = time.time() ret = func(*args, **kwargs) end_time = time.time() print("used:", end_time-start_time) return ret return inner # FBV版添加裝飾器 @wrapper def add_class(request): if request.method == "POST": class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/") return render(request, "add_class.html")
使用裝飾器的CBV
- 類中的方法與獨立函數不完全相同,因此不能直接將函數裝飾器應用於類中的方法 ,我們需要先將其轉換為方法裝飾器。
- Django中提供了method_decorator裝飾器用於將函數裝飾器轉換為方法裝飾器。
- 裝飾器加在類方法上
# 裝飾器加在類方法上 import tinme from django.views import View from django.utils.decorators import method_decorator #導入method_decorator裝飾器 def timer(func): def inner(request, *args, **kwargs): start = time.time() ret = func(request, *args, **kwargs) print("函數執行的時間是{}".format(time.time() - start)) return ret return inner class AddClass(View): @method_decorator(timer)#只有get請求裝飾器才生效 def get(self, request): return render(request, "add_class.html") def post(self, request): class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/")
- dispatch()加裝飾器
# 使用CBV時要注意,請求過來後會先執行dispatch()這個方法,如果需要批量對具體的請求處理方法,如get, post等做一些操作的時候,這裡我們可以手動改寫dispatch方法,這個dispatch方法就和在FBV上加裝飾器的效果一樣。 import tinme from django.views import View from django.utils.decorators import method_decorator #導入方法裝飾器 def timer(func): def inner(request, *args, **kwargs): start = time.time() ret = func(request, *args, **kwargs) print("函數執行的時間是{}".format(time.time() - start)) return ret return inner class Login(View): @method_decorator(timer) #相當於給get,post請求都加上了裝飾器 def dispatch(self, request, *args, **kwargs): obj = super(Login,self).dispatch(request, *args, **kwargs) return obj def get(self,request): return render(request,'login.html') def post(self,request): print(request.POST.get('user')) return HttpResponse('Login.post')
- 裝飾器加在類上
#裝飾器加在類上 import tinme from django.views import View from django.utils.decorators import method_decorator #導入方法裝飾器 def timer(func): def inner(request, *args, **kwargs): start = time.time() ret = func(request, *args, **kwargs) print("函數執行的時間是{}".format(time.time() - start)) return ret return inner @method_decorator(timer,name = 'get') #相當於給get請求,加上了裝飾器 @method_decorator(timer,name = 'post')#相當於給post請求,加上了裝飾器 class Login(View): def get(self,request): return render(request,'login.html') def post(self,request): print(request.POST.get('user')) return HttpResponse('Login.post')
使用method_decorator與不使用的區別: """ def timer(func): pritn(func) def inner(request, *args, **kwargs): print(args) start = time.time() ret = func(request, *args, **kwargs) print("函數執行的時間是{}".format(time.time() - start)) return ret """ 不使用用method_decorator func ——》 <function AddPublisher.get at 0x000001FC8C358598> args ——》 (<app01.views.AddPublisher object at 0x000001FC8C432C50>, <WSGIRequest: GET '/add_publisher/'>) 使用method_decorator之後: func ——》 <function method_decorator.<locals>._dec.<locals>._wrapper.<locals>.bound_func at 0x0000015185F7C0D0> args ——》 (<WSGIRequest: GET '/add_publisher/'>,)
作 者:郭楷豐