Итерация по двум спискам в шаблонах Django - PullRequest
30 голосов
/ 10 марта 2010

Я хочу сделать итерацию списка ниже в шаблонах django:

foo = ['foo', 'bar'];
moo = ['moo', 'loo'];

for (a, b) in zip(foo, moo):
    print a, b

код Джанго:

{%for a, b in zip(foo, moo)%}
  {{a}}
  {{b}}
{%endfor%}

Когда я пытаюсь это сделать, я получаю следующую ошибку:

File "/base/python_lib/versions/third_party/django-0.96/django/template/defaulttags.py", line 538, in do_for
    raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents

Как мне это сделать?

Ответы [ 7 ]

56 голосов
/ 21 ноября 2010

Вы можете использовать zip на ваш взгляд:

mylist = zip(list1, list2)
return render(request, 'template.html', {'list': list, ... })

и в вашем шаблоне используйте

{% for item1, item2 in mylist %}

для перебора обоих списков.

Это должно работать со всеми версиями Django.

25 голосов
/ 13 февраля 2013

Просто определите zip как шаблон фильтра :

@register.filter(name='zip')
def zip_lists(a, b):
  return zip(a, b)

Тогда в вашем шаблоне:

{%for a, b in first_list|zip:second_list %}
  {{a}}
  {{b}}
{%endfor%}
18 голосов
/ 10 марта 2010

Можно сделать

{% for ab in mylist %}
    {{ab.0}}
    {{ab.1}}
{% endfor %}

, но вы не можете позвонить на zip в структуре for. Вам нужно сначала сохранить сжатый список в другой переменной, а затем выполнить итерацию по нему.

7 голосов
/ 19 января 2011

Я построил django-multiforloop , чтобы решить эту проблему. ОТ README:

При установленном django-multiforloop рендеринг этого шаблона

{% for x in x_list; y in y_list %}
  {{ x }}:{{ y }}
{% endfor %}

с этим контекстом

context = {
    "x_list": ('one', 1, 'carrot'),
    "y_list": ('two', 2, 'orange')
}

выдаст

one:two
1:2
carrot:orange
2 голосов
/ 20 октября 2014

Здесь изменен шаблонный тег {% for%}, который позволяет повторять несколько списков одновременно, распаковывая их до:

import re

from itertools import izip
from django import template
from django.template.base import TemplateSyntaxError
from django.template.defaulttags import ForNode

register = template.Library()


class ZipExpression(object):
    def __init__(self, var):
        self.var = var

    def resolve(self, *args, **kwargs):
        return izip(*(
            f.resolve(*args, **kwargs) for f in self.var
        ))


@register.tag('for')
def do_for(parser, token):
    """
    For tag with ziping multiple iterables.
    """
    bits = token.contents.split()
    if len(bits) < 4:
        raise TemplateSyntaxError("'foreach' statements should have at least"
                                  " four words: %s" % token.contents)

    is_reversed = False
    try:
        in_index = bits.index('in')
        sequence = bits[in_index+1:]
        if sequence[-1] == 'reversed':
            is_reversed = True
            sequence.pop()
        if not sequence or 'in' in sequence:
            raise ValueError
        sequence = re.split(r' *, *', ' '.join(sequence))
    except ValueError:
        raise TemplateSyntaxError(
            "'foreach' statements should use the format"
            " 'foreach a,b,(...) in x,y,(...)': %s" % token.contents)

    loopvars = re.split(r' *, *', ' '.join(bits[1:in_index]))
    for var in loopvars:
        if not var or ' ' in var:
            raise TemplateSyntaxError("'foreach' tag received an invalid"
                                      " argumewnt: %s" % token.contents)

    if len(sequence) > 1:
        sequence = ZipExpression(map(parser.compile_filter, sequence))
    else:
        sequence = parser.compile_filter(sequence[0])

    nodelist_loop = parser.parse(('empty', 'endfor',))
    token = parser.next_token()
    if token.contents == 'empty':
        nodelist_empty = parser.parse(('endfor',))
        parser.delete_first_token()
    else:
        nodelist_empty = None
    return ForNode(
        loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty)

Просто сохраните его как библиотеку шаблонов и импортируйте его в свой шаблон. Он переопределит встроенный тег {% for%} (не беспокойтесь, он обратно совместим с ним).

Пример использования:

{% for a,b in foo, moo %}
    {{ a }}
    {{ b }}
{% endfor %}
1 голос
/ 16 сентября 2011

Вы можете настроить свойства объектов foo для объектов moo на стороне сервера.

for f, b in zip(foo, bar):
    f.foosBar = b

context = {
    "foo": foo
}

Это особенно чисто, когда второй список - это свойства первого (что обычно имеет место).

users = User.objects.all()
for user in users:
    user.bestFriend = findBestFriendForUser(user)

context = {
    "users": users
}
0 голосов
/ 27 декабря 2018

В views.py:

foo = ['foo', 'bar']
moo = ['moo', 'loo']
zipped_list = zip(foo,moo)
return render(request,"template.html",{"context":zipped_list}

В template.html:

{% for f,m in context%}
 {{f}}{{m}}
{% endfor %}

Если f - это набор запросов, возвращаемый из базы данных, тогда получить к нему доступ {{f.required_attribute_name}}

...