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 django-developers@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.
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