Frage

Ich habe ein Template-Filter, der eine sehr einfache Aufgabe ausführt und funktioniert gut, aber ich möchte ein Dekorateur auf, es zu benutzen. Leider führt der Dekorateur einen fiesen django Fehler, die keinen Sinn macht ...

Code, der funktioniert:

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

Mit Ausstatter (nicht funktioniert):

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

Hier ist der Fehler:

  

TemplateSyntaxError bei /

     

eine Ausnahme beim Rendern Erwischt:   Pop aus leerer Liste

Ich habe versucht, Bruchstellen innerhalb der Dekorateur Einstellung und ich bin ziemlich sicher, dass es nicht einmal genannt wird ...

Aber nur für den Fall, hier ist der Dekorateur (ich weiß, jemand danach fragen)

Ich ersetzen den Dekorateur (vorübergehend) mit einem Mock Dekorateur, der nichts tut, aber ich habe immer noch die gleichen Fehler

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

Bearbeiten BESTÄTIGT : Es wird verursacht, weil der Dekorateur *args und **kwargs nimmt? Ich gehe davon ist pop() Filter mindestens ein arg alle, um sicherzustellen, genannt zu werden?

den Dekorateur diese Veränderung behebt das Problem:

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

Leider, dass ruiniert die generische Natur des Dekorateur: / was jetzt tun

?
War es hilfreich?

Lösung

Final Answer: ein zusätzliches Argument für den Dekorateur hinzufügen angibt, was eingerichtet wird

Es kann etwas eleganter sein, aber das funktioniert.

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top