我有这个装饰器,如果share
参数是True
(由中间件处理)我不希望执行视图,用于装饰django视图
class no_share(object):
def __init__(self, view):
self.view = view
def __call__(self, request, *args, **kwargs):
"""Don't let them in if it's shared"""
if kwargs.get('shared', True):
from django.http import Http404
raise Http404('not availiable for sharing')
return self.view(request, *args, **kwargs)
目前的工作原理如下:
@no_share
def prefs(request, [...])
但是我想稍微扩展一下这个功能,所以它会像这样工作:
@no_share('prefs')
def prefs(request, [...])
我的问题是如何修改这个装饰器类以便它接受额外的参数?
答案 0 :(得分:7)
我希望布鲁斯·埃克尔的this文章有所帮助。
<强> UPD:强> 根据文章,您的代码将如下所示:
class no_share(object):
def __init__(self, arg1):
self.arg1 = arg1
def __call__(self, f):
"""Don't let them in if it's shared"""
# Do something with the argument passed to the decorator.
print 'Decorator arguments:', self.arg1
def wrapped_f(request, *args, **kwargs):
if kwargs.get('shared', True):
from django.http import Http404
raise Http404('not availiable for sharing')
f(request, *args, **kwargs)
return wrapped_f
根据需要使用:
@no_share('prefs')
def prefs(request, [...])
答案 1 :(得分:4)
Li0liQ提到的Bruce Eckel article应该有助于解决这个问题。具有和不带参数的装饰器的行为略有不同。最大的区别在于,当你传递参数时,__ call__方法会在__init__上被调用一次,并且它应该返回一个函数,只要调用了修饰函数,就会调用该函数。当没有参数时,每次调用修饰函数时都会调用__call__方法。
这对你意味着什么?为@no_arg_decorator
调用__init__和__call__的方式与为@decorator('with','args')
调用的方式不同。
这里有两个装饰器,可能会为你解决问题。只要你总是将它与括号一起使用,你就可以使用@no_share_on(...)装饰器。
def sharing_check(view, attr_name, request, *args, **kwargs):
if kwargs.get(attr_name, True):
from django.http import Http404
raise Http404('not availiable for sharing')
return view(request, *args, **kwargs)
class no_share(object):
"""A decorator w/o arguments. Usage:
@no_share
def f(request):
...
"""
def __init__(self, view):
self.view = view
def __call__(self, request, *args, **kwargs):
return sharing_check(self.view, 'sharing', request, *args, **kwargs)
class no_share_on(object):
"""A decorator w/ arguments. Usage:
@no_share_on('something')
def f(request):
...
--OR--
@no_share_on()
def g(request):
...
"""
def __init__(self, attr_name='sharing'):
self.attr_name = attr_name
def __call__(self, view):
def wrapper_f(request, *args, **kwargs):
return sharing_check(view, self.attr_name, request, *args, **kwargs)
答案 2 :(得分:1)
class no_share(object):
def __init__(self, foo, view):
self.foo = foo
self.view = view
答案 3 :(得分:1)
我认为封闭可能在这里有用。
def no_share(attr):
def _no_share(decorated):
def func(self, request, *args, **kwargs):
"""Don't let them in if it's shared"""
if kwargs.get(attr, True):
from django.http import Http404
raise Http404('not availiable for sharing')
return decorated(request, *args, **kwargs)
return func
return _no_share
答案 4 :(得分:0)
由于你似乎在某处弄错了,这里有一个更完整的例子,可以帮助你看到你做错了什么。使用它作为插入应该有效。
class no_share(object):
def __init__(self, view, attr_name):
self.view = view
self.attr_name = attr_name
def __call__(self, request, *args, **kwargs):
"""Don't let them in if it's shared"""
if kwargs.get(self.attr_name, True):
from django.http import Http404
raise Http404('not availiable for sharing')
return self.view(request, *args, **kwargs)
答案 5 :(得分:0)
我知道这有点晚了......但我没有看到任何提及这种做事的方式(可能是因为问题被提出时它不存在),但为了完整性的利益 我发现看看Django自己如何实现这样的事情很有用。看看:
django.views.decorators.http.require_http_methods https://github.com/django/django/blob/master/django/views/decorators/http.py
from functools import wraps
from django.utils.decorators import decorator_from_middleware, available_attrs
def require_http_methods(request_method_list):
"""
Decorator to make a view only accept particular request methods. Usage::
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
Note that request methods should be in uppercase.
"""
def decorator(func):
@wraps(func, assigned=available_attrs(func))
def inner(request, *args, **kwargs):
# .. do stuff here
return func(request, *args, **kwargs)
return inner
return decorator