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/'>,)

作 者:郭楷豐