以函數的方式定義的視圖稱爲函數視圖html
def register(request): """處理註冊""" # 獲取請求方法,判斷是GET/POST請求 if request.method == 'GET': # 處理GET請求,返回註冊頁面 return render(request, 'register.html') else: # 處理POST請求,實現註冊邏輯 return HttpResponse('這裏實現註冊邏輯')
在Django中也可使用類來定義一個視圖,稱爲類視圖。django
服務器
""" # django的類視圖一共提供了多個以http請求方法命名的類方法給咱們使用。 # 當客戶端使用不一樣的http請求方法訪問當前視圖類,django會根據請求方法訪問到當前類視圖中的同名對象方法中。 # http經常使用請求方法 # GET 客戶端向服務端請求讀取數據 # POST 客戶端向服務器請求建立數據 # PUT 客戶端向服務器請求修改數據[所有] # PATCH 客戶端向服務器請求修改數據[修改部分數據] # DELETE 客戶端向服務器請求刪除數據 """ from django.views import View from django.http.response import HttpResponse class UserView(View): def post(self,request): print("客戶端進行post請求") return HttpResponse("post") def get(self,request): print("客戶端進行get請求") return HttpResponse("get") def put(self,request): print("客戶端進行put請求") return HttpResponse("put") def delete(self,request): print("客戶端進行delete請求") return HttpResponse("delete")
類視圖的好處:app
代碼可讀性好ide
類視圖相對於函數視圖有更高的複用性, 若是其餘地方須要用到某個類視圖的某個特定邏輯,直接繼承該類視圖便可函數
定義類視圖須要繼承自Django提供的父類View,可以使用from django.views.generic import View
或者from django.views.generic.base import View
導入,定義方式如上所示。源碼分析
配置路由時,使用類視圖的as_view()方法來添加post
from django.urls import path from . import views urlpatterns = [ path("cls/", views.UserView.as_view() ), ]
class View:######源碼分析:類視圖調用關係 一、 path("cls/", views.UserView.as_view() ), UserView繼承了View類 並調用View的類方法as_view """ 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'] def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in kwargs.items(): setattr(self, key, value) @classonlymethod def as_view(cls, **initkwargs): """Main entry point for a request-response process.""" 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)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.setup(request, *args, **kwargs) if not hasattr(self, 'request'): raise AttributeError( "%s instance has no 'request' attribute. Did you override " "setup() and forget to call super()?" % cls.__name__ ) return self.dispatch(request, *args, **kwargs)######三、view函數中調用了類方法 dispatch view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view ####### 二、執行as_view函數時返回view函數變量 def setup(self, request, *args, **kwargs): """Initialize attributes shared by all view methods.""" self.request = request self.args = args self.kwargs = kwargs 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: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)######四、 判斷UserView類中是否有 請求方式的例如:POST GET 等請求 request.method.lower() 變成小寫 有着返回該類方法的執行結果 def http_method_not_allowed(self, request, *args, **kwargs): logger.warning( 'Method Not Allowed (%s): %s', request.method, request.path, extra={'status_code': 405, 'request': request} ) return HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs): """Handle responding to requests for the OPTIONS HTTP verb.""" response = HttpResponse() response['Allow'] = ', '.join(self._allowed_methods()) response['Content-Length'] = '0' return response def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)]
爲類視圖添加裝飾器,可使用三種方法。url
爲了理解方便,咱們先來定義一個爲函數視圖準備的裝飾器spa
from django.shortcuts import render # Create your views here. from django.views import View from django.http.response import HttpResponse ####普通的裝飾器調用 def my_decorator(func): def wrapper(request, *args, **kwargs): print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(request, *args, **kwargs) return wrapper @my_decorator def decoratordemo(request): return HttpResponse("函數視圖") """不能直接在類視圖的方法中直接使用裝飾器,會出現參數位置的錯誤,會多傳遞一個self當前對象給裝飾器,從而致使錯誤""" # class UAPI(View): # @my_decorator # def get(self,request): # return HttpResponse("類視圖使用裝飾器") class UAPI2(View): def get(self,request): return HttpResponse("類視圖使用裝飾器")
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), # path("cls/", views.UserView.as_view() ), path("fbv/", views.decoratordemo), path("cbv2/", views.my_decorator(views.UAPI2.as_view())), # 在路由中使用裝飾器很差!很差維護,不易理解 ]
def my_decorator(func): def wrapper(self,request, *args, **kwargs): print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(self,request, *args, **kwargs) return wrapper # @my_decorator # def decoratordemo(request): # return HttpResponse("函數視圖") """不能直接在類視圖的方法中直接使用裝飾器,會出現參數位置的錯誤,會多傳遞一個self當前對象給裝飾器,從而致使錯誤""" class UAPI(View): @my_decorator def get(self,request): return HttpResponse("類視圖使用裝飾器")
method_decorator裝飾器還支持使用name參數指明被裝飾的方法
方式二:
from django.shortcuts import render # Create your views here. from django.views import View from django.http.response import HttpResponse ####普通的裝飾器調用 def my_decorator(func): def wrapper(request, *args, **kwargs): print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(request, *args, **kwargs) return wrapper """要裝飾類方法,可使用django.utils.decorators.method_decorator裝飾器來裝飾""" from django.utils.decorators import method_decorator #第一版本 # class UAPI3(View): # @method_decorator(my_decorator) # def get(self,request): # return HttpResponse("類視圖get方法使用裝飾器") # # @method_decorator(my_decorator) # def post(self,request): # return HttpResponse("類視圖post方法使用裝飾器") #升級版本 # 在開發中,通常不建議在類中的方法上面添加裝飾器,而是建議寫在類的前面 # @method_decorator(my_decorator,name="get") # @method_decorator(my_decorator,name="post") # class UAPI3(View): # def get(self,request): # return HttpResponse("類視圖get方法使用裝飾器") # # def post(self,request): # return HttpResponse("類視圖post方法使用裝飾器") #升級版本 """若是同一個類中全部方法公用一個裝飾器,把裝飾器添加到dispatch中,由於類視圖中任意一個方法都會執行到as_view,as_view裏面必然調用了當前對象的dispatch""" @method_decorator(my_decorator,name="dispatch") class UAPI3(View): def get(self,request): return HttpResponse("類視圖get方法使用裝飾器") def post(self,request): return HttpResponse("類視圖post方法使用裝飾器")
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path("cbv3/", views.UAPI3.as_view()), ]
方式三:
from django.shortcuts import render # Create your views here. from django.views import View from django.http.response import HttpResponse ####普通的裝飾器調用 def my_decorator(func): def wrapper(request, *args, **kwargs): print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(request, *args, **kwargs) return wrapper """要裝飾類方法,可使用django.utils.decorators.method_decorator裝飾器來裝飾""" from django.utils.decorators import method_decorator """在多個類視圖中若是要公用代碼,可使用多繼承[Mixin擴展類]""" @method_decorator(my_decorator,name='dispatch') class BaseView(View): pass class UAPI4(BaseView): def get(self,request): return HttpResponse("類視圖4get方法使用裝飾器") def post(self,request): return HttpResponse("類視圖4post方法使用裝飾器") class MyDecoratorMixin(object): @classmethod def as_view(cls, *args, **kwargs): print( super() ) # View view = super().as_view(*args, **kwargs) # 進行裝飾 view = my_decorator(view) return view class DemoView(MyDecoratorMixin, View): def get(self, request): print('get方法') return HttpResponse('getok') def post(self, request): print('post方法') return HttpResponse('postok')
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path("cbv4/", views.UAPI4.as_view()), path("cbv5/", views.DemoView.as_view()), ]