Django 之 CBV
Django 中有兩種編寫方式,F(xiàn)BV 和 CBV,那么什么是 FBV,CBV 又是什么呢?
一、什么是 CBV
FBV(function base views) 就是在視圖里使用函數(shù)處理請(qǐng)求(常見)。
CBV(class base views) 就是在視圖里使用類處理請(qǐng)求。
示例:
1、project/urls.py
from django.contrib import admin
from django.urls import path
from app.views import IndexView
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', IndexView.as_view()),
]
2、app/views.py
from django.shortcuts import render, HttpResponse
from django.views import View
class IndexView(View):
def get(self, request, *args, **kwargs):
print('get')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
print('post')
return HttpResponse('POST')
可以看到所有的請(qǐng)求都是在類 IndexView 中處理的,它繼承 View,不管是什么請(qǐng)求,都可以匹配到。
二、源碼分析
1、CBV 在進(jìn)行路由匹配時(shí),執(zhí)行 as_view() 方法,它是類 View 中的一個(gè)方法,源碼 base.py:
class View:
@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.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
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
2、從上面的源碼中我們可以看到 as_view(),返回 view() 方法。而 view() 又調(diào)用執(zhí)行 self.dispatch(request, *args, **kwargs) 方法:
def dispatch(self, request, *args, **kwargs):
"""
首先要判斷請(qǐng)求方法是不是在 self.http_method_names 中(即允許的方法列表中)
通過反射,匹配相應(yīng)方法 get、post、put、delete 等
"""
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) # 如果匹配上了,就執(zhí)行它,get(requesr, *args, **kwargs)
http_method_names:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
3、因此大致的執(zhí)行流程為:
請(qǐng)求過來(lái)先執(zhí)行 URL 中的 as_view() 方法
as_view() 返回 view() 方法
而 view() 方法又調(diào)用執(zhí)行 dispatch() 方法
在 dispatch() 中通過反射的方式來(lái)匹配相應(yīng)的請(qǐng)求,是 get 請(qǐng)求,就執(zhí)行 get() 方法,如果是 post 請(qǐng)求的就執(zhí)行 post() 方法。
三、重寫 dispatch
從上面我們指定 CBV 中,請(qǐng)求過來(lái),執(zhí)行相應(yīng)視圖函數(shù)之前,都會(huì)先執(zhí)行 dispatch() 方法。那么如果我們想在處理請(qǐng)求前執(zhí)行某個(gè)方法或者就打印點(diǎn)別的東西,我們可以重寫它。
方法一
from django.shortcuts import render, HttpResponse
from django.views import View
class IndexView(View):
def dispatch(self, request, *args, **kwargs):
print('before...')
func = getattr(self, request.method.lower())
ret = func(self, request, *args, **kwargs)
print('after...')
return ret
def get(self, request, *args, **kwargs):
print('get')
return HttpResponse('GET')
def post(self, request, *args, **kwargs):
print('post')
return HttpResponse('POST')
運(yùn)行結(jié)果如下:
before...
get
after...
當(dāng)有很多個(gè)類的時(shí)候,不可能每個(gè)類都寫一個(gè),可以寫一個(gè)基類,其他類繼承基類即可:
class BasePatch(object):
def dispatch(self, request, *args, **kwargs):
print('before...')
func = getattr(self, request.method.lower())
ret = func(self, request, *args, **kwargs)
print('after...')
return ret
class IndexView(BasePatch, View):
pass
這樣 IndexView 就會(huì)先去找基類 BaseView 中的 dispatch() 方法,而不是 View 中的。
方法二
也可以繼承父類的 dispatch(),不用自己寫反射邏輯:
class BasePatch(object):
def dispatch(self, request, *args, **kwargs):
print('before...')
ret = super(BasePatch, self).dispatch(request, *args, **kwargs)
print('after...')
return ret
四、CSRF
CBV 中如果想給某個(gè)函數(shù)免除 csrf_token 認(rèn)證,可以通過裝飾器的形式實(shí)現(xiàn),但是需要注意的是,裝飾器必須裝飾在類上或者 dispatch 上。
方法一
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class IndexView(View):
@method_decorator(csrf_exempt) # 這句
def dispatch(self, request, *args, **kwargs):
print('before...')
func = getattr(self, request.method.lower())
ret = func(self, request, *args, **kwargs)
print('after...')
return ret
方法二
裝飾在類上,不用 dispatch:
@method_decorator(csrf_exempt, name='dispatch')
class IndexView(View):
def get(self, request, *args, **kwargs):
pass
總結(jié)
以上是生活随笔為你收集整理的Django 之 CBV的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装VMware 置灰正确解决办法
- 下一篇: MyBatis Plus