CBV执行的大致流程
以 views.Login.as_view() 为例:
- 执行views页面中的Login类中的as_view方法
- 执行as_view方法中的view方法
- 执行dispatch方法
- 在dispatch方法中进行判断:
- if request.method.lower() in ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']: ==> 通过反射去执行 ;
- else ==> return http.HttpResponseNotAllowed(self._allowed_methods())
CBV执行的具体流程
还是以 views.Login.as_view() 为例: 在视图中写类时都是继承于View类, 而as_view方法就是View类的一个classonlymethod; 也就是说: 路由中执行的是Login类的父类View中的
as_view方法 ; 在as_view方法中将Login实例化的对象复制给self, as_view方法的最后调用dispatch方法; dispatch方法判断request.method.lower()是否在8种请求方法中: 如果在, 通过反
射执行该方法( 就是我们在视图中的Login类下面写的方法 ) ; 如果不在, 就执行http_method_not_allowed方法, 这个方法返回一个http.HttpResponseNotAllowed: 页面会提醒405
具体代码 :
class View(object):
...
@classonlymethod
def as_view(cls, **initkwargs):
...
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)
...
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)
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())
CBV加装饰器
为视图中的类加装饰器和函数加装饰器情况不同, 尤其是有的装饰器既需要加在函数上, 也需要加在类中方法上. 这时如果不用method_decorator, 可能会导致报错( 因为类中方法比普通函数多一个self
).
# 建议使用method_decorator
from django.utils.decorators import method_decorator
根据加装饰器的需求不同, 这里粗略的分成三种情况:
直接加在类中方法上
# 类中只有一个或者几个方法需要装饰器, 而这个类中有些方法不需要装饰器
@method_decorator(装饰器名)
def get(self, request, *args, **kwargs):
直接加在类上
# 效果和上面差不多, 但是加在类中的某个方法上, 如果是多个方法都需要,可以重复写多个
@method_decorator(装饰器名,name='类中某个方法名')
class EditTest(View):
# 为类中所有方法都加装饰器: 因为类中方法的执行, 最后都是通过View类中的dispatch方法执行的
@method_decorator(装饰器名,name='dispatch')
class EditTest(View):
加在dispatch方法上
# 效果 和 加在类上,指定方法名为dispatch的方式一样: 为类中方法全部加装饰器
class EditTest(View):
@method_decorator(装饰器名)
def dispatch(self, request, *args, **kwargs):
super(EditTest, self).dispatch(request, *args, **kwargs)