Шаблоны Django: Группировка предметов в тройках - PullRequest
5 голосов
/ 10 мая 2009

У меня странная проблема с Джанго. У меня есть набор объектов, которые я перебираю в шаблоне, как обычно. Тем не менее, мне нужно сгруппировать предметы по три. Макет страницы выглядит следующим образом:

Картина 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
Д Е С К Р И П Т И О Н 6

и т. Д.

Я не могу определиться с лучшим набором тегов Django, чтобы сделать это действительно. Это кажется немного сложным. выражение {% cycle%} не очень помогло.

Если, конечно, я выполняю какой-нибудь хакерский скрипт на Java и оставляю Django вне этого? Должно быть что-то вроде «Поместите все описания div друг за другом» или подобное. Не уверен, как лучше играть с этим заказом. Какие-нибудь мысли? Приветствия.

Ответы [ 6 ]

6 голосов
/ 10 сентября 2011

Вы можете использовать простой фильтр для этого:

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 %}
5 голосов
/ 10 мая 2009

Всякий раз, когда вы испытываете сложный код внутри шаблонов, обычно это хороший признак того, что его следует перенести в другое место. Одно из альтернативных решений уже было предложено - переместить код в функцию просмотра.

Другим решением было бы раскрыть функциональность через новый тег шаблона. Одна из причин, по которой вы выбрали бы это решение вместо решения для просмотра, заключается в том, что вы сможете легко повторно использовать код для страниц, которые обслуживаются в разных представлениях.

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 %}
5 голосов
/ 10 мая 2009

Как насчет этих строк:

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

Будет ли это хорошо для вас?

3 голосов
/ 10 мая 2009

Юваль находится в правильных строках, но похоже, что вы хотите пройтись по списку картин дважды: один раз, чтобы отобразить имена (по три в строке), и один для описания. Это не так просто сделать на языке шаблонов.

Я бы посоветовал посмотреть, сможете ли вы что-то сделать с помощью 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 голосов
/ 10 мая 2009

Я определенно голосую за создание структуры в вашем представлении и передачу ее вашему шаблону в правильной форме.

Если вы сталкиваетесь с логикой шаблонов, это признак того, что вы должны выполнять больше работы в своем представлении. (это также научило меня, что довольно много моей логики взгляда нужно было отодвинуть назад в мои модели ...)

0 голосов
/ 10 мая 2009
{% 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-му объекту в списке объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...