django的类视图,CBV:
咱们在开始接触django的时候,习惯于使用函数编写视图,即FBV。使用FBV时,咱们只须要在路由匹配时,对应的路由下找到这个函数就能够了,这样作看似很和谐,可是有的时候,譬如说,当咱们须要根据同一个url请求方法的不一样而去执行不一样的操做时,若是使用FBV去编写视图,那么咱们就须要在视图函数中不断地去执行if request.method=='请求方法' 去判断要去执行什么内容,此时的代码就显得不是很优雅。可是此时若是咱们使用CBV的方式来编写视图,一样的需求,代码就会显得优雅不少,下面就让我来介绍一下CBV的具体实现:python
在django中使用CBV编写视图:
一、首先咱们自定义的视图类须要继承django.views.View类
二、在视图类中定义以'请求方法名称小'写为名称的方法,这样在执行不一样的请求方法的时候就回去自动执行对应的函数
三、在路由映射的时候,要执行这个试图类的as_view()方法,注意这个方法继承自django.views.View数据库
示例代码以下:
'views.py'文件:
from django.views import View
from django.http import HttpResponsedjango
class UserInfoView(View):app
def get(self, request, *args, **kwargs):
return HttpResponse('get user')函数
def post(self, request, *args, **kwargs):
return HttpResponse('post user')源码分析
def delete(self, request, *args, **kwargs):
return HttpResponse('delete user')post
'url.py'文件
from app import views
urlpatterns = [
path('user/', views.UserInfoView.as_view())
]atom
上述示例代码就能够根据同一个url执行不一样的方法时去执行不一样的操做url
CBV实现的源码分析:
一、请求进来,路由找到试图类并执行as_view方法,执行这个方法时其实会返回一个view函数,所以能够看作请求进来以后会先执行试图类的view方法,源码以下:
@classonlymethod
def as_view(cls, **initkwargs):
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))spa
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
update_wrapper(view, cls, updated=())
update_wrapper(view, cls.dispatch, assigned=())
return view
二、从上面的源码中能够看出执行view方法,实际上就是返回self.dispatch方法,也就是说会去执行self.dispatch方法
三、由于试图类自己没有定义dispatch方法,那么在执行dispatch方法的时候就须要去其父类里面查找,而父类里面的dispatch方法则会根据请求方法的不一样基于python类的反射去找到相应的方法,而后执行,这样就会自动实现根据请求方法的不一样去执行不一样的内容了,dispatch方法的源码以下:
def dispatch(self, request, *args, **kwargs):
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)
CBV之添加装饰器:
在咱们使用函数试图FBV的时候,若是咱们想要给其加上一个装饰器,直接加就能够了,例如,在建立django项目的时候,默认全局使用csrf防御,若是咱们想要在某个函数试图上不使用CSRF保护,那么咱们能够给这个视图函数直接添加一个装饰器便可,示例代码以下:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def index(request):
return HttpResponse('index')
可是,当咱们想要给CBV添加装饰器,那么咱们须要作的就不是在其内部的方法上添加,若是和FBV同样直接添加到方法上,那么这不会起任何做用。在CBV上添加装饰器的方法有两种,第一种是重写父类的dispatch方法,并将装饰器添加到dispatch方法上,与此同时在CBV上添加装饰器最好使用django.utils.decorators.method_decorator方法进行包裹。第二种方法则是直接添加在类上,只不过这时你须要使用django.utils.decorators.method_decorator来进行封装。下面的例子是咱们在django中针对重要的数据操做,想要实现数据库的事件特性而添加的装饰器:
一、方法一:
from django.utils.decorators import method_decorator
from django.db import transaction
class OrderView(View):
@method_decorator(transaction.atomic)
def dispatch(self, request, *args, **kwargs):
return super(OrderView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def patch(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass
二、方法二:
from django.utils.decorators import method_decorator
from django.db import transaction
@method_decorator(transaction.atomic, name='dispatch')
class OrderView(View):
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def patch(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass