﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
29253	method_decorator() with list argument doesn't copy over attributes of the decorator function	Chris Jerdonek	Chris Jerdonek	"The [https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/#decorating-the-class docs say] that the ""list"" form of `@method_decorator` is equivalent to invoking it multiple times:

{{{#!python
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'
}}}

However, it appears there is a slight difference in behavior. For example:

{{{#!python
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

def my_decorator(func):
    def new_func(*args, **kwargs):
        func(*args, **kwargs)

    return new_func

@method_decorator(my_decorator, name='dispatch')
@method_decorator(csrf_exempt, name='dispatch')
class View1:

    def dispatch(self):
        pass

@method_decorator([my_decorator, csrf_exempt], name='dispatch')
class View2:

    def dispatch(self):
        pass

print(hasattr(View1.dispatch, 'csrf_exempt'))
print(hasattr(View2.dispatch, 'csrf_exempt'))
}}}

results in the output--

{{{
True
False
}}}

It appears this is because `method_decorator()` takes a [https://github.com/django/django/blob/ee7f51c66dfc1700ff065dfeb5fe2388cc2e9619/django/utils/decorators.py#L51 short cut] when processing a list. It doesn't carry over the attributes of the decorated function like it does in the normal case.
"	Bug	closed	Utilities	2.0	Normal	fixed	decorators		Accepted	1	0	0	0	0	0
