小谈CBV执行过程

CBV执行的大致流程

以 views.Login.as_view() 为例:

  1. 执行views页面中的Login类中的as_view方法
  2. 执行as_view方法中的view方法
  3. 执行dispatch方法
  4. 在dispatch方法中进行判断:
    1. if request.method.lower() in ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']: ==> 通过反射去执行 ;
    2. 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)
posted @ 2020-02-21 00:05  richard_A  阅读(153)  评论(0编辑  收藏  举报