Python Django模板过滤器上的装饰器?
我有一个模板过滤器,它执行一个非常简单的任务,并且工作得很好,但是我想在它上面使用一个装饰器。不幸的是,装饰程序导致了一个令人讨厌的django错误,没有任何意义 有效的代码:Python Django模板过滤器上的装饰器?,python,django,django-templates,filter,templatetags,Python,Django,Django Templates,Filter,Templatetags,我有一个模板过滤器,它执行一个非常简单的任务,并且工作得很好,但是我想在它上面使用一个装饰器。不幸的是,装饰程序导致了一个令人讨厌的django错误,没有任何意义 有效的代码: @register.filter(name="has_network") def has_network(profile, network): hasnetworkfunc = getattr(profile, "has_%s" % network) return hasnetworkfunc() 与D
@register.filter(name="has_network")
def has_network(profile, network):
hasnetworkfunc = getattr(profile, "has_%s" % network)
return hasnetworkfunc()
与Decorator(不起作用):
以下是错误:
模板语法错误位于/
呈现时捕获到异常:
从空列表中弹出
我已经尝试在装饰器内设置断点,我有理由相信它甚至没有被称为
但以防万一,这里是装饰师(我知道有人会要它)
我(暂时)用一个不做任何事情的模拟装饰器替换了装饰器,但是我仍然得到相同的错误
def cache_function(cache_timeout):
def wrapper(fn):
def decorator(*args, **kwargs):
return fn(*args, **kwargs)
return decorator
return wrapper
编辑确认:这是因为装饰程序使用了*args
和**kwargs
?我假设调用了pop()
,以确保所有筛选器都至少包含一个arg
将装饰器更改为此可修复此问题:
def cache_function(cache_timeout):
def wrapper(fn):
def decorator(arg1, arg2):
return fn(arg1, arg2)
return decorator
return wrapper
不幸的是,这破坏了装饰器的一般性质:/现在该怎么办?最终答案:向装饰器添加一个额外的参数,指示装饰的内容 也许有更优雅的东西,但这是可行的
from django.core.cache import cache
from django.db.models.query import QuerySet
try:
from cPickle import dumps
except:
from pickle import dumps
from hashlib import sha1
cache_miss = object()
class CantPickleAQuerySet(Exception): pass
def cache_function(cache_timeout, func_type='generic'):
def wrapper(fn):
def decorator(*args, **kwargs):
try:
cache_indentifiers = "%s%s%s%s" % (
fn.__module__,
fn.__name__,
dumps(args),
dumps(kwargs)
)
except Exception, e:
print "Error: %s\nFailed to generate cache key: %s%s" % (e, fn.__module__, fn.__name__)
return fn(*args, **kwargs)
cache_key = sha1(cache_indentifiers).hexdigest()
value = cache.get(cache_key, cache_miss)
if value is cache_miss:
value = fn(*args, **kwargs)
if isinstance(value, QuerySet):
raise CantPickleAQuerySet("You can't cache a queryset. But you CAN cache a list! just convert your Queryset (the value you were returning) to a list like so `return list(queryset)`")
try:
cache.set(cache_key, value, cache_timeout)
except Exception, e:
print "Error: %s\nFailed to cache: %s\nvalue: %s" % (e, cache_indentifiers, value)
return value
no_arg2 = object()
def filter_decorator(arg1, arg2=no_arg2):
if arg2 is no_arg2:
return decorator(arg1)
else:
return decorator(arg1, arg2)
if func_type == 'generic':
return decorator
elif func_type == 'filter':
return filter_decorator
return wrapper
from django.core.cache import cache
from django.db.models.query import QuerySet
try:
from cPickle import dumps
except:
from pickle import dumps
from hashlib import sha1
cache_miss = object()
class CantPickleAQuerySet(Exception): pass
def cache_function(cache_timeout, func_type='generic'):
def wrapper(fn):
def decorator(*args, **kwargs):
try:
cache_indentifiers = "%s%s%s%s" % (
fn.__module__,
fn.__name__,
dumps(args),
dumps(kwargs)
)
except Exception, e:
print "Error: %s\nFailed to generate cache key: %s%s" % (e, fn.__module__, fn.__name__)
return fn(*args, **kwargs)
cache_key = sha1(cache_indentifiers).hexdigest()
value = cache.get(cache_key, cache_miss)
if value is cache_miss:
value = fn(*args, **kwargs)
if isinstance(value, QuerySet):
raise CantPickleAQuerySet("You can't cache a queryset. But you CAN cache a list! just convert your Queryset (the value you were returning) to a list like so `return list(queryset)`")
try:
cache.set(cache_key, value, cache_timeout)
except Exception, e:
print "Error: %s\nFailed to cache: %s\nvalue: %s" % (e, cache_indentifiers, value)
return value
no_arg2 = object()
def filter_decorator(arg1, arg2=no_arg2):
if arg2 is no_arg2:
return decorator(arg1)
else:
return decorator(arg1, arg2)
if func_type == 'generic':
return decorator
elif func_type == 'filter':
return filter_decorator
return wrapper