2010-06-28 17 views

Respuesta

22

tiene dos opciones:

1. Se definen los objetos para que pueda acceder a los elementos como parámetros

for x in list: 
    {{x.item1}}, {{x.item2}}, {{x.item3}} 

Tenga en cuenta que usted tiene que hacer la lista mediante la combinación de los tres listas:

lst = [{'item1': t[0], 'item2': t[1], 'item3':t[2]} for t in zip(list_a, list_b, list_c)] 

2. Se definen su propio filtro

from django import template 

register = template.Library() 

@register.filter(name='list_iter') 
def list_iter(lists): 
    list_a, list_b, list_c = lists 

    for x, y, z in zip(list_a, list_b, list_c): 
     yield (x, y, z) 

# test the filter 
for x in list_iter((list_a, list_b, list_c)): 
    print x 

Ver las filter documentation

+0

¡Gracias una tonelada! Solución perfecta. – demos

+0

¿Cómo usaría la solución 2 en una plantilla? – webtweakers

6

Abusar de las plantillas de Django:

{% for x in list_a %} 
{% with forloop.counter|cut:" " as index %} 
    {{ x }}, 
    {{ list_b|slice:index|last }}, 
    {{ list_c|slice:index|last }} <br/> 
{% endwith %} 
{% endfor %} 

pero nunca hacer eso !!! solo usa zip en Tus vistas.

+1

¡Buen hack! :) Podría ser útil algún día. – demos

+0

Buen truco Muy útil para mí –

1

plantilla personalizada Tag

from django import template 

register = template.Library() 

def parse_tokens(parser, bits): 
    """ 
    Parse a tag bits (split tokens) and return a list on kwargs (from bits of the fu=bar) and a list of arguments. 
    """ 

    kwargs = {} 
    args = [] 
    for bit in bits[1:]: 
     try: 
      try: 
       pair = bit.split('=') 
       kwargs[str(pair[0])] = parser.compile_filter(pair[1]) 
      except IndexError: 
       args.append(parser.compile_filter(bit)) 
     except TypeError: 
      raise template.TemplateSyntaxError('Bad argument "%s" for tag "%s"' % (bit, bits[0])) 

    return args, kwargs 

class ZipLongestNode(template.Node): 
    """ 
    Zip multiple lists into one using the longest to determine the size 

    Usage: {% zip_longest list1 list2 <list3...> as items %} 
    """ 
    def __init__(self, *args, **kwargs): 
     self.lists = args 
     self.varname = kwargs['varname'] 

    def render(self, context): 
     lists = [e.resolve(context) for e in self.lists] 

     if self.varname is not None: 
      context[self.varname] = [i for i in map(lambda *a: a, *lists)] 
     return '' 

@register.tag 
def zip_longest(parser, token): 
    bits = token.contents.split() 
    varname = None 
    if bits[-2] == 'as': 
     varname = bits[-1] 
     del bits[-2:] 
    else: 
     # raise exception 
     pass 
    args, kwargs = parse_tokens(parser, bits) 

    if varname: 
     kwargs['varname'] = varname 

    return ZipLongestNode(*args, **kwargs) 

Uso:

{% zip_longest list1 list2 as items %} 

Esto le permite pasar 2 o más listas de una etiqueta a continuación, iterar sobre la variable artículos. Si usas más de dos listas, entonces necesitarás repetirlo desafortunadamente. Sin embargo, con dos listas que he usado el primer y último filtros dentro del bucle de esta manera:

{% for item in items %} 
    {% with item|first as one %} 
    {% with item|last as two %} 
    <p>{{ one }}</p> 
    <p>{{ two }}</p> 
    {% endwith %} 
    {% endwith %} 
{% endfor %} 

Sin embargo, después de haber construido todo esto, podría ser mejor hacer esto en una vista!

itertools de Python

También debe considerar itertools de Python, que tiene el método izip_longest que toma dos o más listas. Devuelve las listas como una usando la lista más larga para determinar el tamaño (si desea concatenar a la lista más corta, no busque más allá de izip). Puede elegir con qué vaciar los valores vacíos utilizando la palabra clave fillvalue, pero de manera predeterminada, esto es Ninguno.

Tanto izip_longest como izip devuelven un iterador en lugar de una lista, por lo que podría ver cierta ganancia de rendimiento en sitios más grandes.

Es importante tener en cuenta que izip_longest podría golpear el db un poco más de lo necesario dependiendo de cómo determine la longitud de cada lista (realizar un conteo() sería una llamada adicional al db). Sin embargo, no he podido probar esto de manera confiable y solo importaría una vez que tuvieras que escalar.

Cuestiones relacionadas