2011-12-19 17 views
8

En cada vista de mi aplicación necesito tener el menú de navegación preparado. Así que ahora mismo en cada vista ejecuto una consulta complicada y almaceno el menú en un diccionario que se pasa a una plantilla. En las plantillas, la variable en la que tengo los datos está rodeada de "caché", así que aunque las consultas son bastante costosas, no me molesta."Carga difusa" de datos de un procesador de contexto

Pero no quiero repetirme en cada vista. Supuse que el mejor lugar para preparar el menú es en mi propio procesador de contexto. Y entonces escribí uno, pero noté que incluso cuando no uso los datos del procesador de contexto, se ejecutan las consultas utilizadas para preparar el menú. ¿Hay alguna forma de "cargar de forma perezosa" esos datos desde CP o tengo que usar caché de "bajo nivel" en CP? ¿O tal vez hay una mejor solución para mi problema?

+0

¿qué tal un caso: Bloque de los demás en su procesador de contexto para comprobar si el datos son necesarios o no? –

+0

puede escribir una etiqueta personalizada, que se calcula solo cuando se usa – kosii

Respuesta

18

Django tiene un SimpleLazyObject. En Django 1.3, esto es utilizado por auth context processor (source code). Esto hace que user esté disponible en el contexto de plantilla para cada consulta, pero al usuario solo se accede cuando la plantilla contiene {{ user }}.

Debería poder hacer algo similar en su procesador de contexto.

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

    return { 
     'result': SimpleLazyObject(complicated_query) 
3

Si pasa un objeto invocable al contexto de la plantilla, Django lo evaluará cuando se use en la plantilla. Esto proporciona una manera simple de hacer la pereza - sólo tiene que pasar en callables:

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

El problema con esto es que no memoize la llamada - si lo usa varias veces, complicated_query es llamado varias veces.

La solución es usar algo como SimpleLazyObject como en la otra respuesta, o para usar algo como esto memoize decorador:

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} 

O, si la función ya existe, lo haría así:

from somewhere import complicated_query 

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

yo preferiría este método sobre SimpleLazyObject ya que este último puede producir algunos strange bugs sometimes.

(I fue el que originalmente implementada LazyObject y SimpleLazyObject, y descubierto por mí mismo que no hay maldición sobre cualquier artefacto código de la etiqueta simple.)

Cuestiones relacionadas