我对Django有一个奇怪的问题。我有一组像往常一样在模板中循环的对象。但是,我需要将这些项目分组。页面的布局如下:
绘画1 - 绘画2 - 绘画3
D E S C R I P T I O N 1
D E S C R I P T I O N 2
D E S C R I P T I O N 3
绘画4 - 绘画 - 5绘画6
D E S C R I P T I O N 4
D E S C R I P T I O N 5
D E S C R I P T I O N 6
等等
我无法弄清楚最好的Django标签集来做到这一点。这似乎有点棘手。 {%cycle%}语句没什么帮助。
除非当然,我会做一些某种类型的Java脚本,并将Django排除在外?必须有人说“把所有的描述divs放在一起”或类似的东西。不确定如何最好地使用此订购。有什么想法吗?欢呼声。
答案 0 :(得分:6)
您可以使用简单的过滤器:
import itertools
from django import template
register = template.Library()
@register.filter
def chunks(value, chunk_length):
"""
Breaks a list up into a list of lists of size <chunk_length>
"""
clen = int(chunk_length)
i = iter(value)
while True:
chunk = list(itertools.islice(i, clen))
if chunk:
yield chunk
else:
break
然后在你的模板中:
{% for chunk in paintings|chunks:3 %}
<div class="row">
{% for painting in chunk %}
<div>{{ painting }}</div>
{% endfor %}
</div>
{% endfor %}
答案 1 :(得分:5)
关于这些方面的内容如何:
{% for p in paintingss %}
<div class="painting">whatever</div>
{% if forloop.counter|divisibleby:"3" %}
<br>
{% endif %}
{% endfor %}
这对你有好处吗?
答案 2 :(得分:5)
每当你发现自己在模板中尝试复杂的代码时,它通常是一个很好的迹象,它应该被移动到其他地方。已经提出了一种替代解决方案,即将代码移动到您的视图函数中。
另一种解决方案是通过新的模板标签公开功能。您在视图解决方案中选择此解决方案的原因之一是,您将能够轻松地为使用不同视图的页面重用代码。
class GroupPaintingsNode(template.Node):
def __init__(self, num, varname):
self.num, self.varname = int(num), varname
def render(self, context):
paintings = Painting.objects.all # do your fetching/filtering here..
l = [[] for i in range(len(paintings))]
i = 0
while i < len(paintings):
l[i].append([p.title for p in paintings[i:i+self.num]])
l[i].append([p.desc for p in paintings[i:i+self.num]])
i += self.num
context[self.varname] = l
return ''
def group_paintings(parser, token):
tokens = token.contents.split()
if len(tokens) != 4:
raise template.TemplateSyntaxError, "'%s' tag requires three arguments" % tokens[0]
if tokens[2] != 'as':
raise template.TemplateSyntaxError, "Second argument to '%s' tag must be 'as'" % tokens[0]
return GroupPaintingsNode(tokens[1], tokens[3])
group_paintings = register.tag(group_paintings)
在模板代码中,您可以像这样使用它:
{% group_paintings 3 as paintings %}
{% for p in paintings %}
{% for title in p.0 %} {{ title }} {% endfor %}<br>
{% for desc in p.1 %} {{ desc }} {% endfor %}
{% endfor %}
答案 3 :(得分:3)
Yuval在右边,但看起来好像你想要两次遍历绘画列表:一次显示名称(每行三个),一次用于描述。这在模板语言中并不容易实现。
我建议您查看是否可以使用某些CSS执行某些操作。应该可以为名称和/或描述div分配一个类,以便名称全部浮动在一起,并且描述显示为下面的块。但是仍然很棘手。
或者,您可以在视图中预处理列表,以便将名称和描述分成三个一组。您希望最终得到这种结构:
[
[name1, name2, name3],
[description1, description2, description3],
[name4, name5, name6],
[description4, description5, description6],
...
]
所以你可以尝试这样做:
painting_list = []
counter = 0
while counter < len(paintings):
painting_list.append([p.name for p in paintings[counter:counter+3])
painting_list.append([p.description for p in paintings[counter:counter+3])
counter += 3
然后在你的模板中:
{% for group in painting_list %}
<div class="names">{% for name in group.0 %}{{ name }} {% endfor %}</div>
<ul class="descriptions">
{% for description in group.1 %}
<li>{{ description }}</li>
{% endfor %}
</ul>
{% endfor %}
答案 4 :(得分:2)
我绝对投票支持在您的视图中创建结构并以正确的形式将其传递给您的模板。
如果您发现自己在模板逻辑上苦苦挣扎,那么您应该在视图中完成更多工作。 (这也告诉我,我的视图逻辑需要被推回到我的模型中......)
答案 5 :(得分:0)
{% for painting in painting_list %}
<div class="painting">{{ painting }}</div>
{% if forloop.counter|divisibleby:"3" %}
<br>
{{ description_list.forloop.counter0-2 }}
{{ description_list.forloop.counter0-1 }}
{{ description_list.forloop.counter0 }}
{% endif %}
{% endfor %}
只是让你知道这段代码不起作用,但这样的东西就是你想要的。
也许你可以拿出自己的模板标签来访问对象列表中的第n个对象。