1 ..類視圖
1.1 類視圖引入
以函數(shù)的方式定義的視圖稱為函數(shù)視圖灶似,函數(shù)視圖便于理解浸剩。但是遇到一個(gè)視圖對(duì)應(yīng)的路徑提供了多種不同HTTP請求方式的支持時(shí)伏嗜,便需要在一個(gè)函數(shù)中編寫不同的業(yè)務(wù)邏輯刻获,代碼可讀性與復(fù)用性都不佳坪创。
def register(request):
? ? """處理注冊"""
? ? # 獲取請求方法塌鸯,判斷是GET/POST請求
? ? if request.method == 'GET':
? ? ? ? # 處理GET請求侍瑟,返回注冊頁面
? ? ? ? return render(request, 'register.html')
? ? else:
? ? ? ? # 處理POST請求,實(shí)現(xiàn)注冊邏輯
? ? ? ? return HttpResponse('這里實(shí)現(xiàn)注冊邏輯')
在Django中也可以使用類來定義一個(gè)視圖丙猬,稱為類視圖涨颜。
使用類視圖可以將視圖對(duì)應(yīng)的不同請求方式以類中的不同方法來區(qū)別定義。如下所示
from django.views.generic import View
class RegisterView(View):
? ? """類視圖:處理注冊"""
? ? def get(self, request):
? ? ? ? """處理GET請求茧球,返回注冊頁面"""
? ? ? ? return render(request, 'register.html')
? ? def post(self, request):
? ? ? ? """處理POST請求庭瑰,實(shí)現(xiàn)注冊邏輯"""
? ? ? ? return HttpResponse('這里實(shí)現(xiàn)注冊邏輯')
類視圖的好處:
代碼可讀性好
類視圖相對(duì)于函數(shù)視圖有更高的復(fù)用性, 如果其他地方需要用到某個(gè)類視圖的某個(gè)特定邏輯抢埋,直接繼承該類視圖即可
1.2 類視圖使用
定義類視圖需要繼承自Django提供的父類View弹灭,可使用from django.views.generic import View或者from django.views.generic.base import View 導(dǎo)入,定義方式如上所示揪垄。
配置路由時(shí)穷吮,使用類視圖的as_view()方法來添加。
urlpatterns = [
? ? # 視圖函數(shù):注冊
? ? # url(r'^register/$', views.register, name='register'),
? ? # 類視圖:注冊
? ? url(r'^register/$', views.RegisterView.as_view(), name='register'),
]
1.3 類視圖原理
? ? @classonlymethod
? ? def 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
? ? ? ? ? ? # 調(diào)用dispatch方法饥努,按照不同請求方式調(diào)用不同請求方法
? ? ? ? ? ? return self.dispatch(request, *args, **kwargs)
? ? ? ? ...省略代碼...
? ? ? ? # 返回真正的函數(shù)視圖
? ? ? ? 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)
1.4 類視圖使用裝飾器
為類視圖添加裝飾器捡鱼,可以使用三種方法。
為了理解方便酷愧,我們先來定義一個(gè)為函數(shù)視圖準(zhǔn)備的裝飾器(在設(shè)計(jì)裝飾器時(shí)基本都以函數(shù)視圖作為考慮的被裝飾對(duì)象)驾诈,及一個(gè)要被裝飾的類視圖。
def my_decorator(func):
? ? def wrapper(request, *args, **kwargs):
? ? ? ? print('自定義裝飾器被調(diào)用了')
? ? ? ? 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')
1.4.1 在URL配置中裝飾
urlpatterns = [
? ? url(r'^demo/$', my_decorate(DemoView.as_view()))
]
在類視圖中使用為函數(shù)視圖準(zhǔn)備的裝飾器時(shí)溶浴,不能直接添加裝飾器翘鸭,需要使用method_decorator將其轉(zhuǎn)換為適用于類視圖方法的裝飾器。
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參數(shù)指明被裝飾的方法
# 為全部請求方法添加裝飾器
@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???
為函數(shù)視圖準(zhǔn)備的裝飾器戳葵,其被調(diào)用時(shí)就乓,第一個(gè)參數(shù)用于接收request對(duì)象
def my_decorate(func):
? ? def wrapper(request, *args, **kwargs):? # 第一個(gè)參數(shù)request對(duì)象
? ? ? ? ...代碼省略...
? ? ? ? return func(request, *args, **kwargs)
? ? return wrapper
而類視圖中請求方法被調(diào)用時(shí),傳入的第一個(gè)參數(shù)不是request對(duì)象,而是self 視圖對(duì)象本身生蚁,第二個(gè)位置參數(shù)才是request對(duì)象
class DemoView(View):
? ? def dispatch(self, request, *args, **kwargs):
? ? ? ? ...代碼省略...
? ? def get(self, request):
? ? ? ? ...代碼省略...
所以如果直接將用于函數(shù)視圖的裝飾器裝飾類視圖方法噩翠,會(huì)導(dǎo)致參數(shù)傳遞出現(xiàn)問題。
method_decorator的作用是為函數(shù)視圖裝飾器補(bǔ)充第一個(gè)self參數(shù)邦投,以適配類視圖方法伤锚。
如果將裝飾器本身改為可以適配類視圖方法的,類似如下志衣,則無需再使用method_decorator屯援。
def my_decorator(func):
? ? def wrapper(self, request, *args, **kwargs):? # 此處增加了self
? ? ? ? print('自定義裝飾器被調(diào)用了')
? ? ? ? print('請求路徑%s' % request.path)
? ? ? ? return func(self, request, *args, **kwargs)? # 此處增加了self
? ? return wrapper
2.中間件
目的: 知道中間件中的代碼和視圖函數(shù)中的代碼, 執(zhí)行的時(shí)間順序
使用流程:
1, 創(chuàng)建文件,定義中間件方法; booktest/my_middleware.py
defsimple_middleware(get_response):
# 此處編寫的代碼僅在Django第一次配置和初始化的時(shí)候執(zhí)行一次。
print("1, init")
defmiddleware(request):
# 此處編寫的代碼會(huì)在每個(gè)請求處理視圖前被調(diào)用念脯。
print("1, before_request")
?
response=get_response(request)
?
# 此處編寫的代碼會(huì)在每個(gè)請求處理視圖之后被調(diào)用狞洋。
print("1, after_request")
?
returnresponse
?
returnmiddleware
2,注冊中間件列表; settings.py
MIDDLEWARE= [
?? ...
'booktest.my_middleware.simple_middleware',
]
調(diào)用流程圖解