代码之家  ›  专栏  ›  技术社区  ›  Jiaaro

Django模板过滤器上的装饰器?

  •  1
  • Jiaaro  · 技术社区  · 15 年前

    有效的代码:

    @register.filter(name="has_network")
    def has_network(profile, network):
        hasnetworkfunc = getattr(profile, "has_%s" % network)
        return hasnetworkfunc()
    

    与Decorator(不起作用):

    @register.filter(name="has_network")
    @cache_function(30)
    def has_network(profile, network):
        hasnetworkfunc = getattr(profile, "has_%s" % network)
        return hasnetworkfunc()
    

    呈现时捕获到异常: 从空列表中弹出

    我已经尝试在装饰器内设置断点,我有理由相信它甚至没有被称为。。。

    但以防万一,这里是装饰师(我知道有人会要它)

    我(暂时)用一个不做任何事情的模拟装饰器替换了装饰器,但是我仍然得到相同的错误

    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
    

    不幸的是,这破坏了装饰器的通用性:/n现在该怎么办?

    1 回复  |  直到 15 年前
        1
  •  0
  •   Jiaaro    15 年前

    最终答案:向装饰器添加一个额外的参数,指示要装饰的内容

    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