Зачем мне украшать декоратор login_required с помощью @method_decorator

Я пытаюсь понять код миксинов, опубликованных в этой записи блога.

Эти примеси вызывают декоратор login_required из django.contrib.auth.decorators внутри примесей, но они делают это с помощью декоратора method_decorator из 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) 

person harijay    schedule 05.03.2012    source источник


Ответы (1)


Метод Django_decorator настроен на правильную передачу аргумента self декорированной функции. Причина, по которой это не отображается в тестовых примерах, которые вы написали выше с декоратором run_eight_times, заключается в том, что inner_func в run_eight_times вслепую передает все аргументы в myfunc через *args и **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 — преобразует первую подпись во вторую.

person Mike Fogel    schedule 05.03.2012