版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
Django内置method_decorator
method_decorator属于django.utils.decorators,用于将函数装饰器转为类方法装饰器,直白的说,就是被method_decorator包裹的装饰器可用于装饰类或类方法。
用法
1.装饰类方法
将需要的装饰器包裹在method_decorator中装饰在目标类方法上。
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required) # 将登录验证装饰器包裹在需要此功能的类方法上
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
2.装饰类
method_decorator可以直接装饰一个类,但这样做需要给定’name’参数,即指明装饰类中的哪些方法。对于类试图而言,这些方法主要包括dispatch(), get(), post(), delete()等。
@method_decorator(login_required, name='dispatch') # 指明装饰dispatch方法
class ProtectedView(TemplateView):
template_name = 'secret.html'
3.需要多个装饰器的情况
当一个类需要添加多个装饰器时,可以将他们放在一个列表或元组中。
decorators = [never_cache, login_required] # 将需要的装饰器放在一个列表中
# 装饰器会按照列表中的顺序装饰目标对象
@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
也可以采用依次装饰的方式
@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
template_name = 'secret.html'
4.另一种方式
这种对类或类方法的装饰也可以采用Mixin的方法,既定以一个Mixin类,将装饰器的功能封装在这个类中,并在定义目标类时,使其先继承Mixin类。
源码
在django.utils.decorators.py中可以看到这个功能的源码。
from contextlib import ContextDecorator # noqa
from functools import WRAPPER_ASSIGNMENTS, partial, update_wrapper, wraps
class classonlymethod(classmethod):
def __get__(self, instance, cls=None):
pass
def _update_method_wrapper(_wrapper, decorator):
pass
def _multi_decorate(decorators, method):
pass
def method_decorator(decorator, name=''):
"""
Convert a function decorator into a method decorator
"""
# 'obj' can be a class or a function. If 'obj' is a function at the time it
# is passed to _dec, it will eventually be a method of the class it is
# defined on. If 'obj' is a class, the 'name' is required to be the name
# of the method that will be decorated.
def _dec(obj):
if not isinstance(obj, type):
return _multi_decorate(decorator, obj)
if not (name and hasattr(obj, name)):
raise ValueError(
"The keyword argument `name` must be the name of a method "
"of the decorated class: %s. Got '%s' instead." % (obj, name)
)
method = getattr(obj, name)
if not callable(method):
raise TypeError(
"Cannot decorate '%s' as it isn't a callable attribute of "
"%s (%s)." % (name, obj, method)
)
_wrapper = _multi_decorate(decorator, method)
setattr(obj, name, _wrapper)
return obj
# Don't worry about making _dec look similar to a list/tuple as it's rather
# meaningless.
if not hasattr(decorator, '__iter__'):
update_wrapper(_dec, decorator)
# Change the name to aid debugging.
obj = decorator if hasattr(decorator, '__name__') else decorator.__class__
_dec.__name__ = 'method_decorator(%s)' % obj.__name__
return _dec
参考连接:method_decorator