On 21 October 2010 14:31, Luke Plant <l.plant...@cantab.net> wrote:
> On Thu, 2010-10-21 at 01:40 +0200, Łukasz Rekucki wrote:
>
>> On a related note, while writing a class_decorator() I noticed that
>> method_decorator() doesn't work with decorators that set attributes on
>> the view (like csrf_exempt). This is because the decorator is invoked
>> on a closure inside _wrapper() during method call (i.e. during method
>> call, not class creation), while as_view() only sees _wrapper - which
>> has no attributes.
>
> Good catch!  The attached patch should fix it, but it feels a bit icky,
> due to the double application of the decorator. Let me know if it solves
> this problem for you, or if you can think of a better way to fix it.

I does fell icky. I haven't found a better way to solve this in
general case, so I started thinking about a solution designed for CBV
specifically. Both are a variation on what you proposed earlier:

1) Add get_decorators() class method, that as is called by as_view(),
to get a list of decorators
to be applied on the closure.

class MyView(View):
    @classmethod
    def get_decorators(cls):
        return (login_required,)

This can be folded to a class decorator:

def decorate_class(fdec):
    @wraps(fdec)
    def _decorator(cls):
         original_method = cls.get_decorators
        @wraps(original_method)
        def method_replacement(cls):
            return (fdec,) + original_method()
        cls.get_decorators = method_replacement
        return cls
    return _decorator

@decorate_class(login_required):
class MyView(View):
    pass

2) decorators class property:

class MyView(View):
    decorators = (login_required,)

# in View:

def as_view(cls, **initkwargs):
    # all the stuff now
    # now the hack part that follows MRO
    all_decorators = sum( (c.decorators for c in cls.mro() if
"decorators" in c.__dict__), [])
    for dec in decorators:
        view = dec(view)
    return view

This also can be turned into a class decorator.

-- 
Łukasz Rekucki

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to