2009-05-10 98 views
5

Django有一个奇怪的问题。我有一组对象,即Im通常在模板中循环。但是,我需要将这些项目分成三组。该页面的布局是这样的:Django模板:Threes中的组项目

绘画1 - 油漆2 - 绘画3

说明1
描述2
描述3

绘画4 - 绘画 - 5绘画6

描述4
描述5
DES C R I P T I O 4 N 6

等等等等

我不能完全弄清楚Django的标签最好的一组要做到这一点真的。这似乎有点棘手。 {%cycle%}语句没有太大的帮助。

除非当然,我做了一些java脚本黑客的某种并离开Django这个?必须要说“将所有描述div彼此放在一起”或类似的地方。不知道如何玩这个顺序。有什么想法吗?干杯。

回答

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 %} 
+0

我觉得这似乎是最好的模板标签是这个功能去的最好的地方反对更尴尬的观点。很多列表,但我明白了:)有一些优雅的解决方案!谢谢 :) – Oni 2009-05-11 19:20:51

5

如何是关于围绕这些方针的东西:

{% for p in paintingss %} 
    <div class="painting">whatever</div> 
    {% if forloop.counter|divisibleby:"3" %} 
     <br> 
    {% endif %} 
{% endfor %} 

这会不会对你有好处?

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 %} 
2

我肯定投票支持创建结构在您的视图中,并以正确的形式传递给您的模板。

如果你发现自己在模板逻辑上挣扎,那么这是一个迹象,你应该在视图中做更多的工作。 (这也教会了我相当多的观点逻辑需要被推回到我的模型中......)

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 %} 

只是让你知道这个代码将无法正常工作,但这样的事情是你想要的。

也许你可以想出你自己的templatetag来访问对象列表中的第n个对象。

5

您可以使用一个简单的过滤器这样的:

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 %}