I have a template filter that performs a very simple task and works well, but I would like to use a decorator on it. Unfortunately the decorator causes a nasty django error that doesn't make any sense...
Code that works:
@register.filter(name="has_network")
def has_network(profile, network):
    hasnetworkfunc = getattr(profile, "has_%s" % network)
    return hasnetworkfunc()
With Decorator (doesn't work):
@register.filter(name="has_network")
@cache_function(30)
def has_network(profile, network):
    hasnetworkfunc = getattr(profile, "has_%s" % network)
    return hasnetworkfunc()
Here is the error:
TemplateSyntaxError at /
Caught an exception while rendering: pop from empty list
I have tried setting break points inside the decorator and I am reasonably confident that it is not even being called...
But just in case here is the decorator (I know someone will ask for it)
I replaced the decorator (temporarily) with a mock decorator that does nothing, but I still get the same error
def cache_function(cache_timeout):
    def wrapper(fn):
        def decorator(*args, **kwargs):
            return fn(*args, **kwargs)
        return decorator
    return wrapper
edit CONFIRMED: It is caused because the decorator takes *args and **kwargs? I assume pop() is being called to ensure filters all take at least one arg?
changing the decorator to this fixes the problem:
def cache_function(cache_timeout):
    def wrapper(fn):
        def decorator(arg1, arg2):
            return 开发者_JS百科fn(arg1, arg2)
        return decorator
    return wrapper
Unfortunately that ruins the generic nature of the decorator :/ what to do now?
Final Answer: Add an extra argument to the decorator indicating what is being decorated
There may be something more elegant, but this works.
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
 
         
                                         
                                         
                                         
                                        ![Interactive visualization of a graph in python [closed]](https://www.devze.com/res/2023/04-10/09/92d32fe8c0d22fb96bd6f6e8b7d1f457.gif) 
                                         
                                         
                                         
                                         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论