装饰类视图:Django内置method_decorator

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/JosephThatwho/article/details/101109514

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

猜你喜欢

转载自blog.csdn.net/JosephThatwho/article/details/101109514
今日推荐