9

? Estoy tratando de entender el código para los mixins publicados en this blog post.¿Por qué necesito decorar el decodificador de login_required con @method_decorator

Estos mixins llaman el decorador login_required de django.contrib.auth.decorators dentro de los mixins, pero lo hacen decoradas por el method_decorator de django.utils.decorators. En el código de ejemplo siguiente no entiendo por qué necesito decorar el decorador 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) 

El method_decorator decorador dice que se usa para "Convierte un decorador de la función en un decorador de método" Pero en el código de prueba que puede utilizar mi decorador incluso sin el method_decorator.

Mi decorador

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

Mi clase que llama al decorador anterior produce directamente el mismo resultado que si llamaba a la decoradora decorado por 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) 

Respuesta

15

method_decorator de Django está configurado para pasar el self argumento correctamente a la función decorada. La razón por la que esto no aparece en los casos de prueba que escribió arriba con el decorador run_eight_times es que el inner_func en run_eight_times pasa ciegamente todos los argumentos a myfunc a través de *args y **kwargs. En general, este no será el caso.

Para ver esto con su ejemplo, intente lo siguiente:

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

Específicamente, mira decoradores de Django volverán una función con una firma (request, *args, **kwargs). Para una vista basada en clase, esta debe ser (self, request, *args, **kwargs). Eso es lo que hace method_decorator: transformar la primera firma en la segunda.

Cuestiones relacionadas