2009-12-04 4 views
1

J'ai un filtre de gabarit qui exécute une tâche très simple et fonctionne bien, mais je voudrais utiliser un décorateur dessus. Malheureusement, le décorateur provoque une erreur de django méchant qui ne fait pas de sens ...Décorateurs sur les filtres Gabarit Django?

Code qui fonctionne:

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

Avec Décorateur (ne fonctionne pas):

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

ici est l'erreur:

TemplateSyntaxError at /

Caught an exception while rendering: pop from empty list

J'ai essayé de définir des points de rupture à l'intérieur du décorateur et je suis raisonnable y confiant qu'il est même pas appelé ...

Mais juste au cas où est le décorateur ici (je sais que quelqu'un va demander)

Je remplacé le décorateur (temporairement) avec un décorateur maquette qui ne fait rien, mais je reçois toujours la même erreur

def cache_function(cache_timeout): 
    def wrapper(fn): 
     def decorator(*args, **kwargs): 
      return fn(*args, **kwargs) 
     return decorator 
    return wrapper 

modifier CONFIRMÉ: Il est dû au fait que le décorateur prend *args et **kwargs? Je suppose que pop() est appelé pour s'assurer que tous les filtres prennent au moins un argument?

changer le décorateur à ce résout le problème:

def cache_function(cache_timeout): 
    def wrapper(fn): 
     def decorator(arg1, arg2): 
      return fn(arg1, arg2) 
     return decorator 
    return wrapper 

Malheureusement qui ruine la nature générique du décorateur:/quoi faire maintenant?

Répondre

0

finale Réponse: Ajouter un argument supplémentaire au décorateur indiquant ce qui est décoré

Il peut y avoir quelque chose de plus élégant, mais cela fonctionne.

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 
Questions connexes