Django的类视图和中间件
類視圖
1 類視圖引入
以函數的方式定義的視圖稱為函數視圖,函數視圖便于理解。但是遇到一個視圖對應的路徑提供了多種不同HTTP請求方式的支持時,便需要在一個函數中編寫不同的業務邏輯,代碼可讀性與復用性都不佳。
def register(request):"""處理注冊""" # 獲取請求方法,判斷是GET/POST請求 if request.method == 'GET': # 處理GET請求,返回注冊頁面 return render(request, 'register.html') else: # 處理POST請求,實現注冊邏輯 return HttpResponse('這里實現注冊邏輯')在Django中也可以使用類來定義一個視圖,稱為類視圖。
使用類視圖可以將視圖對應的不同請求方式以類中的不同方法來區別定義。如下所示
from django.views.generic import Viewclass RegisterView(View): """類視圖:處理注冊""" def get(self, request): """處理GET請求,返回注冊頁面""" return render(request, 'register.html') def post(self, request): """處理POST請求,實現注冊邏輯""" return HttpResponse('這里實現注冊邏輯')類視圖的好處:
- 代碼可讀性好
- 類視圖相對于函數視圖有更高的復用性, 如果其他地方需要用到某個類視圖的某個特定邏輯,直接繼承該類視圖即可.
2 類視圖使用
定義類視圖需要繼承自Django提供的父類View,可使用from django.views.generic import View或者from django.views.generic.base import View?導入,定義方式如上所示。
配置路由時,使用類視圖的as_view()方法來添加。
urlpatterns = [# 視圖函數:注冊# url(r'^register/$', views.register, name='register'),# 類視圖:注冊url(r'^register/$', views.RegisterView.as_view(), name='register'), ]3 類視圖原理
@classonlymethoddef as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ ...省略代碼... def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs # 調用dispatch方法,按照不同請求方式調用不同請求方法 return self.dispatch(request, *args, **kwargs) ...省略代碼... # 返回真正的函數視圖 return view 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)4 類視圖使用裝飾器
為類視圖添加裝飾器,可以使用三種方法。
為了理解方便,我們先來定義一個為函數視圖準備的裝飾器(在設計裝飾器時基本都以函數視圖作為考慮的被裝飾對象),及一個要被裝飾的類視圖。
def my_decorator(func):def wrapper(request, *args, **kwargs): print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(request, *args, **kwargs) return wrapper class DemoView(View): def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok')4.1 在URL配置中裝飾
urlpatterns = [url(r'^demo/$', my_decorate(DemoView.as_view())) ]此種方式最簡單,但因裝飾行為被放置到了url配置中,單看視圖的時候無法知道此視圖還被添加了裝飾器,不利于代碼的完整性,不建議使用。
此種方式會為類視圖中的所有請求方法都加上裝飾器行為(因為是在視圖入口處,分發請求方式前)。
4.2 在類視圖中裝飾
在類視圖中使用為函數視圖準備的裝飾器時,不能直接添加裝飾器,需要使用method_decorator將其轉換為適用于類視圖方法的裝飾器。
from django.utils.decorators import method_decorator# 為全部請求方法添加裝飾器 class DemoView(View): @method_decorator(my_decorator) def dispatch(self, *args, **kwargs): return super().dispatch(*args, **kwargs) def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok') # 為特定請求方法添加裝飾器 class DemoView(View): @method_decorator(my_decorator) def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok')method_decorator裝飾器還支持使用name參數指明被裝飾的方法
# 為全部請求方法添加裝飾器 @method_decorator(my_decorator, name='dispatch') class DemoView(View): def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok') # 為特定請求方法添加裝飾器 @method_decorator(my_decorator, name='get') class DemoView(View): def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok')為什么需要使用method_decorator呢
為函數視圖準備的裝飾器,其被調用時,第一個參數用于接收request對象
def my_decorate(func):def wrapper(request, *args, **kwargs): # 第一個參數request對象 ...代碼省略... return func(request, *args, **kwargs) return wrapper而類視圖中請求方法被調用時,傳入的第一個參數不是request對象,而是self 視圖對象本身,第二個位置參數才是request對象
class DemoView(View):def dispatch(self, request, *args, **kwargs): ...pass... def get(self, request): ...pass...所以如果直接將用于函數視圖的裝飾器裝飾類視圖方法,會導致參數傳遞出現問題。
method_decorator的作用是為函數視圖裝飾器補充第一個self參數,以適配類視圖方法。
如果將裝飾器本身改為可以適配類視圖方法的,類似如下,則無需再使用method_decorator。
def my_decorator(func):def wrapper(self, request, *args, **kwargs): # 此處增加了self print('自定義裝飾器被調用了') print('請求路徑%s' % request.path) return func(self, request, *args, **kwargs) # 此處增加了self return wrapper4.3 構造Mixin擴展類
使用面向對象多繼承的特性.?在python3中,類的多繼承的順序會依照C3算法生成的mro來進行查找,遵循廣度優先的原則.
class MyDecoratorMixin(object): @classmethod def as_view(cls, *args, **kwargs): view = super().as_view(*args, **kwargs) view = my_decorator(view) return view class DemoView(MyDecoratorMixin, View): def get(self, request): print('get方法') return HttpResponse('ok') def post(self, request): print('post方法') return HttpResponse('ok')另外一種:
class MyDecoratorMixin(View):
"""
擴展類裝飾器
"""
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
view = my_decorator(view)
return view
class MyDecoratorMixin2(View):
"""
擴展類裝飾器
"""
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
view = my_decorator2(view)
return view
class Registers(MyDecoratorMixin, MyDecoratorMixin2):
"""
注冊類視圖
"""
def get(self,request):
return HttpResponse("get page")
def post(self,request):
return HttpResponse("post page")
使用Mixin擴展類,也會為類視圖的所有請求方法都添加裝飾行為。
?
中間件
Django中的中間件是一個輕量級、底層的插件系統,可以介入Django的請求和響應處理過程,修改Django的輸入或輸出。中間件的設計為開發者提供了一種無侵入式的開發方式,增強了Django框架的健壯性。
我們可以使用中間件,在Django處理視圖的不同階段對輸入或輸出進行干預。
1 中間件的定義方法
定義一個中間件工廠函數,然后返回一個可以別調用的中間件。
中間件工廠函數需要接收一個可以調用的get_response對象。
返回的中間件也是一個可以被調用的對象,并且像視圖一樣需要接收一個request對象參數,返回一個response對象。
def simple_middleware(get_response):# 此處編寫的代碼僅在Django第一次配置和初始化的時候執行一次。 def middleware(request): # 此處編寫的代碼會在每個請求處理視圖前被調用。 response = get_response(request) # 此處編寫的代碼會在每個請求處理視圖之后被調用。 return response return middleware例如,在users應用中新建一個middleware.py文件,
def my_middleware(get_response):print('init 被調用') def middleware(request): print('before request 被調用') response = get_response(request) print('after response 被調用') return response return middleware定義好中間件后,需要在settings.py 文件中添加注冊中間件
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware',# 'django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'users.middleware.my_middleware', # 添加中間件 ]注意:Django運行在調試模式下,中間件init部分有可能被調用兩次。
2 多個中間件的執行順序,要注意順序
- 在請求視圖被處理前,中間件由上至下依次執行
- 在請求視圖被處理后,中間件由下至上依次執行
?
轉載于:https://www.cnblogs.com/yinjiangchong/p/9255904.html
總結
以上是生活随笔為你收集整理的Django的类视图和中间件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ2437 [Noi2011]兔兔
- 下一篇: 提升vector性能的几个技巧