2009-09-29 11 views
14

Tengo un filtro currency, que toma un valor en USD y lo convierte a una moneda (ya sea USD o GBP). La moneda a la que convertir se almacena en la sesión, pero los filtros no toman RequestContext, así que no puedo tomarla directamente desde allí.Django - accediendo al RequestContext desde un filtro personalizado

¿Hay una manera mejor que pasar el elemento de sesión relevante en la plantilla, y desde la plantilla en el filtro como argumento? Si bien este enfoque funciona, parece bastante horrible, y es probable que termine pasando la moneda a (casi) cada plantilla.

Mi filtro actualmente se ve algo como esto:

def currency(value, currency): 
    if currency == 'usd': 
     val = '$%.2f' % value 
     return mark_safe(val) 

    d = Decimal(value) 
    val = '£%.2f' % (d*Decimal('0.63')) 

    return mark_safe(val) 

Respuesta

7

Si crea una etiqueta de plantilla en lugar de un filtro, se le da el contexto para trabajar con (que contiene la solicitud). http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags

+1

@Adam - tal vez estoy siendo grosero, pero no puedo ver en esos documentos cómo obtener acceso a las variables de sesión desde dentro de las etiquetas de plantilla personalizadas. ¿Podría darme un ejemplo o señalar lo que me estoy perdiendo? –

+1

Ah - cavar alrededor parece ser pasado como el primer argumento de la etiqueta (acaba de encontrar un ejemplo que agrega una clase a enlaces que coinciden con una expresión regular, que se ve (a) útil y (b) adaptable - http: // gnuvince .wordpress.com/2007/09/14/a-django-template-tag-for-the-current-active-page /). –

+0

Derecha, el contexto es un parámetro estándar del método de representación en el nodo de etiqueta de plantilla. Si necesita un ejemplo específico más, estoy seguro de que podría reunir uno. – Adam

3

Esto se puede hacer utilizando un filtro. Primero asegúrese de tener "django.core.context_processors.request" en usted TEMPLATE_CONTEXT_PROCESSORS. Si no lo hace, se puede añadir esto a su archivo settings.py:

TEMPLATE_CONTEXT_PROCESSORS += (
    "django.core.context_processors.request" 
) 

Luego, en su plantilla, su filtro se verá así (asumiendo que su variable de sesión se llama 'currency_type'):

{{value|currency:request.session.currency_type}} 

¿O es algo como esto lo que está considerando bastante horrible?

+0

Él es; Mira lo que está haciendo, ese filtro describe exactamente lo que estás diciendo. – fijter

+0

Pensé que podría estar quejándose del proceso de tener que pasar explícitamente la variable a través de la vista. Esto lo hará disponible automáticamente. También puedo publicar un ejemplo del uso de una etiqueta de plantilla con takes_context = True en el decorador – Zach

3

Tendría que estar de acuerdo con Adam en que migrar el código a una etiqueta personalizada es la mejor manera.

Sin embargo, un cliente necesitaba registrar el uso de ciertos filtros solo cuando se publicaba una página y tenía un ENORME inventario de plantillas que usaban la sintaxis del filtro existente. Habría sido una tarea costosa reescribir todas las plantillas. Por lo tanto, se me ocurrió con esta simple función que extrae el contexto de la pila de llamadas:

https://gist.github.com/drhoden/e05292e52fd5fc92cc3b

def get_context(max_depth=4): 
    import inspect 
    stack = inspect.stack()[2:max_depth] 
    context = {} 
    for frame_info in stack: 
     frame = frame_info[0] 
     arg_info = inspect.getargvalues(frame) 
     if 'context' in arg_info.locals: 
      context = arg_info.locals['context'] 
      break 
    return context 

Asegúrese de leer mis advertencias, pero esto da acceso a los filtros estándar con el contexto (cuando se está disponible) SIN tener que convertir su filtro en una etiqueta.

+1

Es impresionante, no estoy seguro de si es impresionante en buena o mala manera, pero impresionante;) –

0

Una solución menos hacky a la propuesta de Daniel Rhoden es, utilizar threading.local(). Defina una clase de middleware, que almacena su request como un objeto global dentro de su hilo local, y agregue esa clase a su MIDDLEWARE_CLASSES.

Ahora, un filtro de plantilla puede acceder fácilmente a ese objeto de solicitud.

Cuestiones relacionadas