【发布时间】:2014-12-07 16:10:34
【问题描述】:
我想在装饰器中包装类的方法之一。如果有必要,我的类是基于 django 类的视图。
第一种实现是 method_decorator 的 wrap 方法:
class MyView(View):
template_name = "index.html"
@method_decorator(login_required):
def dispatch(self, *args, **kwargs):
return super(MyView, self).dispatch(*args, **kwargs)
好的,这行得通。但我不想每次都覆盖方法dispatch。
第二种方式 - mixins 和多重继承。
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"
这也有效。但是如果我想使用多个装饰器,则需要列出父母中的所有mixin。这对我来说不是很好。
我想要下一个:
@viewdecorator(login_required)
class MyView(LoginRequiredView, View):
template_name = "index.html"
而我的问题是如何实现viewdecorator。我试着写这个:
def viewdecorator(decorator):
def wrap(cls):
dispatch = getattr(cls, 'dispatch', None)
if dispatch:
setattr(cls, 'dispatch', method_decorator(decorator))
return cls
return wrap
但是这个装饰器中生成的 cls 不包含原始的 classmethods 和 classonlymethods。我猜想这种行为的原因。
如何将viewdecorator写成classmethods会在生成的cls中呈现?
UPD:我通过示例了解了它的工作原理以及下面的实际工作代码
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'
【问题讨论】:
-
那么您的意思是如果
dispatch是classmethod,那么您的viewdecorator将不起作用?classmethod必须是最顶级的装饰器,但也许有一个解决方法。 -
viewdecorator对我来说看起来不错,我不明白你的意思是“这个装饰器中的结果 cls 不包含原始的 classmethods 和 classonlymethods”?它肯定包含所有方法。您还需要将'dispatch'设置为method_decorator(decorator)(dispatch). -
@simonzack 不,你可以把
@classmethod放在任何地方。 -
@AshwiniChaudhary 我不确定,请参阅stackoverflow.com/questions/1987919/…
-
好的,在viewdecorator cls中不包含as_view、dispatch的方法。为什么?
标签: python django metaprogramming decorator