全稱應該是class base views 和function base views
理解起來應該就是基於類的視圖函數和基於函數的視圖函數html
應該是我目前最經常使用的一種方式了,就是給每個views裏的功能添加本身專用的方法。例如若是要對網頁進行get訪問,而後經過得到request中post方式傳遞的form表單獲取數據。shell
from django.http import HttpResponse def login(request): if request.method == 'GET': return HttpResponse('OK1') if request.method =="POST": return HttpResponse('OK2')
。。。
可是這種方法,看起來有點臃腫,查看代碼的時候不容易看清楚你的post請求get請求是在哪裏處理的,因此就有了CBV的處理方法。django
在views文件中:app
from django.views import View class LoginView(View): def get(self,request): return render(request,"login.html") def post(self,request): user=request.POST.get('user') pwd=request.POST.get('pwd')) if Turn: #假使驗證成立 return HttpResponse("OK3")
在CBV的使用中,須要調用父類View
,它會在源碼裏解釋這個CBV的應用範圍,以及運做原理。函數
在urls文件中:post
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/$',views.LoginView.as_view()),
# url(r'^login/$',views.login) ]
綜上所述:
咱們能夠知道設置一個CBV方法,要作的就是,在views裏建立一個類,這個類的父類必定得是View
,並且在urls設置的時候,url指向的再也不是一個函數名,而是你定義的類的.as_view()
方法url
運行起來以後,會發現當向login.html這個url發送get請求的時候,成功,發送post請求的時候,也成功,而且有相應的返回值。spa
翻看源碼,實現以上功能的核心,其實都在那個被繼承的父類View
裏:code
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) @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()) def options(self, request, *args, **kwargs): """ Handles responding to requests for the OPTIONS HTTP verb. """ response = http.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)]
從源碼中咱們能夠看到。這個CBV的核心類,是爲了處理各類請求服務的。其中有一個list來存放這些請求,而且指向他們應該實現的函數功能。
再補充一點,在CBV建立類方法的時候,必定要攜帶一個request參數。而這個參數裏面就攜帶了request.method.lower()
,經過反射,CBV函數天然能處理這些method對應的請求。orm
看源碼的準則就看,看本身看的懂得代碼,應爲源碼的有些高深的設置,咱們先階段還不須要去了解.
首先,無論cbv仍是fbv,在url中都是用戶訪問請求,纔回去執行相應的視圖函數,
cbv在啓動項目的時候,已經在LoginView中執行一段騷操做的獲得一個函數名,咱們如今就來看看:
首先咱們要明確的一點就是一個類.屬性或方法,首先在本身那找,找不到繼承的父類找。因此不能直接點。as_view,
先去類LoginView中找看看有,有沒有方法:
點開View,咱們找到as_view方法,發現是類方法,
前面過程作了什麼咱們無論,返回值只是返回一個view,調用view函數,咱們去看view函數,
view函數最後返回self.dispacth,這裏要注意!!!這個self.dispacth,self是誰,self咱們看代碼發現是LoginView類,
仍是那個準則,調用屬性方法,如今本身那邊找,沒有再找父類。
由於LoginView中沒有dispath這方法,因此仍是執行的父類的dispath方法:
注意點:仍是在調用某個方法時,咱們必定要肯定是誰去調用這個方法!找方法必定先找本身的,沒有再去父類找!
既然在上面咱們查看源碼的時候已經發現,導向專門的method操做的函數是dispatch,並且每一個CBV類的父類都是View,那我能不能在這個dispatch裏面作一些定製化操做,
繼承父類的dispatch
def dispatch(self, request, *args, **kwargs): obj=super(login,self).dispatch(request, *args, **kwargs) return obj # 因爲父類的dispatch最後返回了一個handle,也就是一個返回值,因此在繼承的時候也應該提供一個返回值
裝飾化這個dispatch
def dispatch(self, request, *args, **kwargs): print('123‘) obj=super(login,self).dispatch(request, *args, **kwargs) print('456') return obj
反饋的效果:
不論是什麼方法請求,都必需要打印123,456
總的來講,這個只是一個簡單的示範處理,若是須要對過來的請求作更多的潤色,還須要在這個繼承動做先後作更多工做。須要知道的是,他和裝飾器略微不懂,那就是他能夠共享這個dispatch的request,而且對他進行工做