I want to do the below list iteration in django templates:
我想在django模板中进行如下列表迭代:
foo = ['foo', 'bar'];
moo = ['moo', 'loo'];
for (a, b) in zip(foo, moo):
print a, b
django code:
django代码:
{%for a, b in zip(foo, moo)%}
{{a}}
{{b}}
{%endfor%}
I get the below error when I try this:
当我尝试这个的时候,我得到了下面的错误:
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
How do I accomplish this?
我如何做到这一点?
6 个解决方案
#1
12
It's possible to do
可以做的
{% for ab in mylist %}
{{ab.0}}
{{ab.1}}
{% endfor %}
but you cannot make a call to zip
within the for
structure. You'll have to store the zipped list in another variable first, then iterate over it.
但是不能在for结构中调用zip。您必须先将压缩列表存储在另一个变量中,然后对其进行迭代。
#2
45
You can use zip
in your view:
您可以在您的视图中使用zip:
mylist = zip(list1, list2)
return render_to_response('template.html', {'list': list, ... })
and in your template use
在模板使用中
{% for item1, item2 in mylist %}
to iterate through both lists.
遍历两个列表。
This should work with all version of Django.
这应该适用于所有版本的Django。
#3
21
Simply define zip as a template filter:
简单地定义zip为模板过滤器:
@register.filter(name='zip')
def zip_lists(a, b):
return zip(a, b)
Then, in your template:
然后,在你的模板:
{%for a, b in first_list|zip:second_list %}
{{a}}
{{b}}
{%endfor%}
#4
5
I built django-multiforloop to solve this problem. From the README:
我构建了django-multiforloop来解决这个问题。的自述:
With django-multiforloop installed, rendering this template
安装了django-multiforloop后,呈现此模板
{% for x in x_list; y in y_list %}
{{ x }}:{{ y }}
{% endfor %}
with this context
与这种情况下
context = {
"x_list": ('one', 1, 'carrot'),
"y_list": ('two', 2, 'orange')
}
will output
将输出
one:two
1:2
carrot:orange
#5
2
Here is modified {% for %} templatetag which allows iterating several lists at once izip-ing them before:
这里修改了{% for %} templatetag,允许在之前对多个列表进行一次迭代:
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)
Just save it as templatetag library and import it in your template. It will override build-in {% for %} tag (don't worry it is backward compatible with it).
只需将它保存为templatetag库并将其导入到模板中。它将覆盖内建的{%}标记(不要担心它是向后兼容的)。
Example usage:
使用示例:
{% for a,b in foo, moo %}
{{ a }}
{{ b }}
{% endfor %}
#6
1
You can make the foo objects properties of the moo objects on the server side.
您可以在服务器端创建moo对象的foo对象属性。
for f, b in zip(foo, bar):
f.foosBar = b
context = {
"foo": foo
}
This is especially clean when the second list are properties of the first (which is typically the case).
当第二个列表是第一个列表的属性时(通常是这种情况),这一点尤其清晰。
users = User.objects.all()
for user in users:
user.bestFriend = findBestFriendForUser(user)
context = {
"users": users
}
#1
12
It's possible to do
可以做的
{% for ab in mylist %}
{{ab.0}}
{{ab.1}}
{% endfor %}
but you cannot make a call to zip
within the for
structure. You'll have to store the zipped list in another variable first, then iterate over it.
但是不能在for结构中调用zip。您必须先将压缩列表存储在另一个变量中,然后对其进行迭代。
#2
45
You can use zip
in your view:
您可以在您的视图中使用zip:
mylist = zip(list1, list2)
return render_to_response('template.html', {'list': list, ... })
and in your template use
在模板使用中
{% for item1, item2 in mylist %}
to iterate through both lists.
遍历两个列表。
This should work with all version of Django.
这应该适用于所有版本的Django。
#3
21
Simply define zip as a template filter:
简单地定义zip为模板过滤器:
@register.filter(name='zip')
def zip_lists(a, b):
return zip(a, b)
Then, in your template:
然后,在你的模板:
{%for a, b in first_list|zip:second_list %}
{{a}}
{{b}}
{%endfor%}
#4
5
I built django-multiforloop to solve this problem. From the README:
我构建了django-multiforloop来解决这个问题。的自述:
With django-multiforloop installed, rendering this template
安装了django-multiforloop后,呈现此模板
{% for x in x_list; y in y_list %}
{{ x }}:{{ y }}
{% endfor %}
with this context
与这种情况下
context = {
"x_list": ('one', 1, 'carrot'),
"y_list": ('two', 2, 'orange')
}
will output
将输出
one:two
1:2
carrot:orange
#5
2
Here is modified {% for %} templatetag which allows iterating several lists at once izip-ing them before:
这里修改了{% for %} templatetag,允许在之前对多个列表进行一次迭代:
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)
Just save it as templatetag library and import it in your template. It will override build-in {% for %} tag (don't worry it is backward compatible with it).
只需将它保存为templatetag库并将其导入到模板中。它将覆盖内建的{%}标记(不要担心它是向后兼容的)。
Example usage:
使用示例:
{% for a,b in foo, moo %}
{{ a }}
{{ b }}
{% endfor %}
#6
1
You can make the foo objects properties of the moo objects on the server side.
您可以在服务器端创建moo对象的foo对象属性。
for f, b in zip(foo, bar):
f.foosBar = b
context = {
"foo": foo
}
This is especially clean when the second list are properties of the first (which is typically the case).
当第二个列表是第一个列表的属性时(通常是这种情况),这一点尤其清晰。
users = User.objects.all()
for user in users:
user.bestFriend = findBestFriendForUser(user)
context = {
"users": users
}