2011-12-19 11 views
8

W każdym widoku mojej aplikacji muszę mieć przygotowane menu nawigacyjne. Tak więc teraz w każdym widoku wykonuję skomplikowane zapytanie i przechowuje menu w słowniku, który jest przekazywany do szablonu. W szablonach zmienna, w której mam dane, jest otoczona "pamięcią podręczną", więc nawet jeśli zapytania są dość kosztowne, nie przeszkadza mi to."Lazy load" danych z procesora kontekstowego

Ale nie chcę powtarzać się w każdym widoku. Domyślam się, że najlepszym miejscem do przygotowania menu jest mój procesor kontekstu. Tak więc napisałem jedną, ale zauważyłem, że nawet gdy nie używam danych z procesora kontekstowego, wykonywane są zapytania użyte do przygotowania menu. Czy istnieje sposób na "leniwy ładunek" takich danych z CP lub czy muszę używać pamięci podręcznej "niskiego poziomu" w CP? A może jest lepsze rozwiązanie mojego problemu?

+0

jak o if: inny blok w edytorze kontekstowego, aby sprawdzić, czy dane są potrzebne czy nie? –

+0

można napisać niestandardowy znacznik, który jest obliczany tylko wtedy, gdy jest używany – kosii

Odpowiedz

18

Django ma SimpleLazyObject. W Django 1.3 jest to używane przez auth context processor (source code). To sprawia, że ​​user jest dostępny w kontekście szablonu dla każdego zapytania, ale użytkownik jest dostępny tylko wtedy, gdy szablon zawiera {{ user }}.

Powinieneś być w stanie zrobić coś podobnego w swoim procesorze kontekstowym.

from django.utils.functional import SimpleLazyObject 
def my_context_processor(request): 
    def complicated_query(): 
     do_stuff() 
     return result 

    return { 
     'result': SimpleLazyObject(complicated_query) 
3

Po przekazaniu obiektu wywoływalnego do kontekstu szablonu Django oceni go, gdy zostanie użyty w szablonie. Zapewnia to jeden prosty sposób na to lenistwo - po prostu przekazać w callables:

def my_context_processor(request): 
    def complicated_query(): 
     do_stuff() 
     return result      
    return {'result': complicated_query} 

Problemem jest to, że nie memoize połączenia - jeśli używasz go wiele razy, complicated_query jest wywoływana wielokrotnie.

Rozwiązaniem jest użycie czegoś podobnego SimpleLazyObject jak w innych odpowiedź, lub użyć coś jak ten memoize dekoratora:

def memoize_nullary(f): 
    """ 
    Memoizes a function that takes no arguments. 
    """ 
    def func(): 
     if not hasattr(func, 'retval'): 
      func.retval = f() 
     return func.retval 
    return func 

def my_context_processor(request): 
    @memoize_nullary 
    def complicated_query(): 
     do_stuff() 
     return result      
    return {'result': complicated_query} 

Lub, jeśli funkcja już istnieje, to zrobi to tak:

from somewhere import complicated_query 

def my_context_processor(request):   
    return {'result': memoize_nullary(complicated_query)} 

Wolałbym tę metodę od SimpleLazyObject, ponieważ ta ostatnia może produkować około strange bugs sometimes.

(byłem jedynym, który pierwotnie realizowane LazyObject i SimpleLazyObject i odkrył dla siebie, że nie jest przekleństwo na każdym artefaktem kodu oznaczonego simple.)