I want to wrap one of the methods of class in decorator. If this necessary, my class is django class based view.
First type of implementation is wrap method by method_decorator:
class MyView(View): template_name = "index.html" @method_decorator(login_required): def dispatch(self, *args, **kwargs): return super(MyView, self).dispatch(*args, **kwargs) Ok, this works. But I don't want to every time overwrite method dispatch.
Second way - mixins and multiple inheritance.
class LoginRequiredView(object): @method_decorator(login_required): def dispatch(self, *args, **kwargs): return super(MyView, self).dispatch(*args, **kwargs) class MyView(LoginRequiredView, View): template_name = "index.html" This works too. But if I want to use multiple decorators, it is required to list all mixins in parents. It is not very good for me.
I want next:
@viewdecorator(login_required) class MyView(LoginRequiredView, View): template_name = "index.html" And my question is how to implement viewdecorator. I try to write this:
def viewdecorator(decorator): def wrap(cls): dispatch = getattr(cls, 'dispatch', None) if dispatch: setattr(cls, 'dispatch', method_decorator(decorator)) return cls return wrap But resulting cls in this decorator don't contains original classmethods and classonlymethods. I guess about a reason such behavior.
How to write viewdecorator to classmethods will be presented in resulting cls?
UPD: I understood how this work and below actual working code with example
def viewdecorator(decorator): def wrap(cls): getattribute = cls.__getattribute__ def newgetattr(cls, name): attr = getattribute(cls, name) if name == 'dispatch': return decorator(method_decorator(attr)) return attr cls.__getattribute__ = newgetattr return cls return wrap @viewdecorator(login_required) @viewdecorator(csrf_exempt) class EntriesMyList(EntriesList): template_name = 'index.html'
dispatchis aclassmethod, then yourviewdecoratorwon't work?classmethodmust be the top-most decorators, but maybe there's a workaround.viewdecoratorlooks good to me, I don't understand what you meant by "resulting cls in this decorator don't contains original classmethods and classonlymethods"? It definitely contains all the methods. Also you need to set'dispatch'tomethod_decorator(decorator)(dispatch).@classmethodanywhere.