Why do I need to decorate login_required decorator with @method_decorator

半城伤御伤魂 提交于 2019-12-20 10:42:05

问题


I am trying to understand the code for the mixins posted at this blog post.

These mixins call the login_required decorator from django.contrib.auth.decorators within the mixins , but they do so decorated by the method_decorator from django.utils.decorators. In the sample code below I dont understand why I need to decorate the login_required decorator .

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) 

The method_decorator decorator says it is used to "Converts a function decorator into a method decorator" But in test code I can use my decorator even without the method_decorator.

My decorator

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

My class which calls the above decorator directly produces the same result as if I called the decorator decorated by 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) 

回答1:


Django's method_decorator is set up to pass the self argument in correctly to the decorated function. The reason this doesn't show up in the test cases you wrote above with the run_eight_times decorator is that the inner_func in run_eight_times blindly passes all arguments in to myfunc via *args and **kwargs. In general, this won't be the case.

To see this with your example, try the following:

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()

Specifically, Django's view decorators will return a function with a signature (request, *args, **kwargs). For a class based-view, this should be (self, request, *args, **kwargs). That's what method_decorator does - transform the first signature into the second.



来源:https://stackoverflow.com/questions/9560840/why-do-i-need-to-decorate-login-required-decorator-with-method-decorator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!