2010-09-15 4 views
7

No sé si es posible, pero me gustaría ser capaz de escribir algo como lo siguiente:La creación de una lista sobre la marcha en una plantilla de Django

{% with var1 var2 var3 as some_list %} 
    {{ some_list|maximum }} 
{% endwith %} 

Crear una lista sobre la marcha de un número arbitrario de variables de plantilla y/o literales parece útil, así que tengo la esperanza de haber pasado por alto algo simple.

No obstante, me gustaría saber cómo crear una etiqueta de plantilla que acepte una cantidad arbitraria de argumentos. (He jugado un poco con simple_tag, que funciona bien para las etiquetas que acepten un número fijo de argumentos.)

no quiero ir a la molestia de crear un programa de análisis y subclases django.template.Node hasta que haya comprobado que no hay una solución más simple.

Respuesta

13

Si desea agregar una nueva variable (es decir, some_list), necesitará acceder al contexto de la plantilla, por lo que simple_tag no será suficiente.

Para mí, el primer enfoque es tratar de hacer este tipo de trabajo en la vista, a fin de mantener las plantillas lo más simple posible.

Si ese no es el caso, tendrá que escribir la etiqueta manualmente, así:

@register.tag 
def make_list(parser, token): 
    bits = list(token.split_contents()) 
    if len(bits) >= 4 and bits[-2] == "as": 
    varname = bits[-1] 
    items = bits[1:-2] 
    return MakeListNode(items, varname) 
    else: 
    raise template.TemplateSyntaxError("%r expected format is 'item [item ...] as varname'" % bits[0]) 

class MakeListNode(template.Node): 
    def __init__(self, items, varname): 
    self.items = map(template.Variable, items) 
    self.varname = varname 

    def render(self, context): 
    context[self.varname] = [ i.resolve(context) for i in self.items ] 
    return "" 

y utilizarlo como este para crear una nueva variable some_list:

{% make_list var1 var2 var3 as some_list %} 

dude para darle un nombre mejor!

+2

+1. Esta solución le permite guardar la lista resultante en otra variable, lo que le permite operarla más adelante. –

+0

Gracias, Will. Esto encaja muy bien. La razón por la que el procesamiento en la vista no es una opción es que estoy creando una plantilla para una aplicación Django reutilizable. La vista proporciona una lista completa de elementos. Dentro de la plantilla estoy configurando la cantidad máxima de elementos para mostrar usando '{% con 5 como máximo%}'. Además de mostrar la cantidad adecuada de elementos, incluyo un recuento de visualización en el formulario "mostrando X de elementos Y". X es 'items | length' o' max', el que sea más pequeño. Entonces necesito encontrar el menor de dos valores, uno de los cuales se establece dentro de la plantilla misma. – davidchambers

+0

Debe ser 'len (bits)> 3' en lugar de' len (bits)> 4' para permitir que se cree una lista con un único elemento. – davidchambers

3

Jugué un poco y se me ocurrió una etiqueta que puede aceptar una cantidad variable de argumentos y convertirlos en una lista.

@register.tag('to_list') 
def to_list(_parser, token): 
    try: 
     parts = token.split_contents() 
    except ValueError: 
     raise template.TemplateSyntaxError, \ 
      "%r tag requires at least one argument" % token.contents.split()[0] 

    return AsListNode(parts[1:]) 

class AsListNode(template.Node): 
    def __init__(self, parts): 
     self.parts = map(lambda p: template.Variable(p), parts) 

    def render(self, context): 
     resolved = [] 
     for each in self.parts: 
      resolved.append(each.resolve(context)) 
     return resolved 

Plantilla:

<p>{% to_list var1 var2 var3 %}</p> 

actualización

@solution de Will es mejor. Le permite guardar la lista resultante usando otra variable para que pueda operarla más tarde.

Cuestiones relacionadas