FBV
FBV(function base views) 就是在視圖里使用函數(shù)處理請求鳍怨。
在之前django的學(xué)習(xí)中,我們一直使用的是這種方式傲隶,所以不再贅述鹅经。
CBV
CBV(class base views) 就是在視圖里使用類處理請求寂呛。
Python是一個面向?qū)ο蟮木幊陶Z言,如果只用函數(shù)來開發(fā)瘾晃,有很多面向?qū)ο蟮膬?yōu)點就錯失了(繼承贷痪、封裝、多態(tài))蹦误。所以Django在后來加入了Class-Based-View劫拢。可以讓我們用類寫View强胰。這樣做的優(yōu)點主要下面兩種:
- 提高了代碼的復(fù)用性舱沧,可以使用面向?qū)ο蟮募夹g(shù),比如Mixin(多繼承)
- 可以用不同的函數(shù)針對不同的HTTP方法處理偶洋,而不是通過很多if判斷熟吏,提高代碼可讀性
CBV.as_view()
在Django的路由中為url指定view的時候,如果為類視圖(所有類視圖都需要繼承于基類View)玄窝,則需要使用as_view方法將類視圖轉(zhuǎn)化為一個函數(shù)牵寺,接下來筆者就分析一下as_view方法的源碼。
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']
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 six.iteritems(kwargs):
setattr(self, key, value)
# as_view方法經(jīng)過類方法裝飾器恩脂,是一個類方法
@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
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)
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 http.HttpResponseNotAllowed(self._allowed_methods())
其實as_view方法在方法中定義了一個view函數(shù)帽氓,這個函數(shù)接受的參數(shù)跟FBV接受的參數(shù)一樣,但是這個函數(shù)并不負(fù)責(zé)根據(jù)http的method分配到具體的CBV的method上俩块,而是將這項工作交給了dispatch方法去完成黎休。最后as_view方法返回了這個view函數(shù)浓领。
在dispatch方法中,尋找了開發(fā)者自行定義的諸如get势腮,post等方法對應(yīng)的業(yè)務(wù)邏輯并返回執(zhí)行結(jié)果联贩,如果開發(fā)者沒有定義該方法,則返回405表示該方法不允許捎拯。