10

我正在尝试了解在此博客文章中发布的 mixins 的代码。

这些 mixin 从 mixins 中调用login_required装饰器django.contrib.auth.decorators,但它们是由method_decoratorfrom装饰的django.utils.decorators。在下面的示例代码中,我不明白为什么我需要装饰login_required装饰器。

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
    """
    View mixin which verifies that the user has authenticated.

    NOTE:
        This should be the left-most mixin of a view.
    """
    # Why do I need to decorate login_required here
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(*args, **kwargs) 

method_decorator装饰器说它用于“将函数装饰器转换为方法装饰器”但是在测试代码中,即使没有 method_decorator,我也可以使用我的装饰器。

我的装饰师

def run_eight_times(myfunc):
    def inner_func(*args, **kwargs):
        for i in range(8):
            myfunc(*args, **kwargs)
    return inner_func 

我的类直接调用上述装饰器产生的结果与调用装饰器的结果相同method_decorator

from django.utils.decorators import method_decorator
class Myclass(object):

    def __init__(self,name,favorite_dish):
        self.name = name
        self.favorite_dish = favorite_dish

    # This next line is not required
    #@method_decorator(run_eight_times)
    @run_eight_times
    def undecorated_function(self):
        print "%s likes spam in his favorite dish %s" % (self.name,self.favorite_dish) 
4

1 回答 1

17

Django 的 method_decorator 设置为将self参数正确传递给装饰函数。这没有出现在您上面使用run_eight_times装饰器编写的测试用例中的原因是inner_funcinrun_eight_times盲目地将所有参数通过*argsand传递给 myfunc **kwargs。一般来说,情况不会如此。

要在您的示例中看到这一点,请尝试以下操作:

from django.utils.decorators import method_decorator

def run_eight_times(myfunc):
    def inner_func(what_he_likes, **kwargs):
        # override...
        what_he_likes = 'pizza'
        for i in range(8):
            myfunc(what_he_likes, **kwargs)
    return inner_func

class MyClass(object):

    def __init__(self, name, favorite_dish):
        self.name = name
        self.favorite_dish = favorite_dish

    # This next line required!
    @method_decorator(run_eight_times)
    #@run_eight_times
    def undecorated_function(self, what_he_likes):
        print "%s likes %s in his favorite dish %s" % (
            self.name, what_he_likes, self.favorite_dish
        )

def main():
    inst = MyClass('bob', 'burrito')
    inst.undecorated_function('hammy spam')

if __name__ == '__main__':
    main()

具体来说,Django 的视图装饰器将返回一个带有签名的函数(request, *args, **kwargs)。对于基于类的视图,这应该是(self, request, *args, **kwargs). 就是method_decorator这样 - 将第一个签名转换为第二个。

于 2012-03-05T06:15:35.367 回答