Hello
As a happy user of the class-based views, I wrote a couple of higher-level
decorators to make it easy to apply all the standard decorators to them.
The first is an updated version of method_decorator, made to accept additional
arguments and pass them to the original decorator:
class MyView(View):
@method_decorator(never_cache)
@method_decorator(login_required, login_url='/my-login')
@method_decorator(permission_required, 'thing.change_thing')
def dispatch(self, request, *args, **kwargs):
...
The second is class_view_decorator, to apply classic view decorators to the
newer class-based views:
@class_view_decorator(never_cache)
@class_view_decorator(login_required, login_url='/my-login')
@class_view_decorator(permission_required, 'thing.change_thing')
class MyView(View):
...
In the application I'm developing they seem to be working ok--and saved me
quite a bit of code clutter!
If you approve of this addition, I will develop proper unit tests and
documentation as required.
-Tobia
--
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en.
from functools import update_wrapper
def method_decorator(decorator, *dec_args, **dec_kwargs):
"""
Converts a function decorator into a method decorator, with or without
decorator arguments.
Does not support decorators with call but without arguments: @my_dec()
Example:
@method_decorator(never_cache)
@method_decorator(login_required, login_url='/my-login')
@method_decorator(permission_required, 'thing.change_thing')
def dispatch(self, request, *args, **kwargs):
...
"""
# 'func' is a function at the time it is passed to _dec, but will eventually
# be a method of the class it is defined it.
def _dec(func):
def _wrapper(self, *args, **kwargs):
if dec_args or dec_kwargs:
@decorator(*dec_args, **dec_kwargs)
def bound_func(*args2, **kwargs2):
return func(self, *args2, **kwargs2)
else:
@decorator
def bound_func(*args2, **kwargs2):
return func(self, *args2, **kwargs2)
# bound_func has the signature that 'decorator' expects i.e. no
# 'self' argument, but it is a closure over self so it can call
# 'func' correctly.
return bound_func(*args, **kwargs)
# In case 'decorator' adds attributes to the function it decorates, we
# want to copy those. We don't have access to bound_func in this scope,
# but we can cheat by using it on a dummy function.
if dec_args or dec_kwargs:
@decorator(*dec_args, **dec_kwargs)
def dummy(*args, **kwargs):
pass
else:
@decorator
def dummy(*args, **kwargs):
pass
update_wrapper(_wrapper, dummy)
# Need to preserve any existing attributes of 'func', including the name.
update_wrapper(_wrapper, func)
return _wrapper
update_wrapper(_dec, decorator)
# Change the name to aid debugging.
_dec.__name__ = 'method_decorator(%s)' % decorator.__name__
return _dec
def class_view_decorator(view_decorator, *args, **kwargs):
"""
Converts a function decorator for regular Django views, with or without
decorator arguments, into a class decorator for class-based views.
Example:
@class_view_decorator(never_cache)
@class_view_decorator(login_required, login_url='/my-login')
@class_view_decorator(permission_required, 'thing.change_thing')
class MyView(View):
...
"""
def apply_decorator(cls):
# extend the original class and decorate its dispatch method
class Decorated(cls):
@method_decorator(view_decorator, *args, **kwargs)
def dispatch(self, *args, **kwargs):
return super(Decorated, self).dispatch(*args, **kwargs)
# preserve name and module of the class, for debugging purposes
Decorated.__module__, Decorated.__name__ = cls.__module__, cls.__name__
return Decorated
return apply_decorator