Списки, разделенные запятыми в шаблонах django


Если fruits список ['apples', 'oranges', 'pears'],

есть ли быстрый способ с помощью тегов шаблона django производить "яблоки, апельсины и груши"?

Я знаю, что это не сложно сделать с помощью цикла и {% if counter.last %} заявления, но поскольку я собираюсь использовать это неоднократно, я думаю, что мне придется научиться писать пользовательские теги фильтры, и я не хочу изобретать велосипед, если это уже было сделано.

в качестве расширения, мои попытки отбросить Оксфордская Запятая (т. е. возвращение "яблоки, апельсины и груши") еще грязнее.

9 57

9 ответов:

Я бы предложил пользовательский шаблон django фильтр, а не на заказ tag -- фильтр удобнее и проще (где это уместно, как здесь). {{ fruits | joinby:", " }} похоже, что я хотел бы иметь для этой цели... с обычаем joinby фильтр:

def joinby(value, arg):
    return arg.join(value)

, который, как вы видите, сама простота!

первый выбор: используйте существующий тег шаблона соединения.

http://docs.djangoproject.com/en/dev/ref/templates/builtins/#join

вот пример

{{ value|join:" // " }}

второй вариант: делать это в представлении.

fruits_text = ", ".join( fruits )

обеспечить fruits_text к шаблону для рендеринга.

вот супер простое решение. Поместите этот код в запятую.html:

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}

и теперь, где бы вы ни поставили запятую, включите " запятую.html " вместо этого:

{% for cat in cats %}
Kitty {{cat.name}}{% include "comma.html" %}
{% endfor %}

на шаблоне Django это все, что вам нужно сделать для установления запятой после каждого плода. Запятая остановится, как только она достигнет последнего плода.

{% if not forloop.last %}, {% endif %}

вот фильтр я написал, чтобы решить мою проблему:

def join_with_commas(obj_list):
    """Takes a list of objects and returns their unicode representations,
    seperated by commas and with 'and' between the penultimate and final items
    For example, for a list of fruit objects:
    [<Fruit: apples>,<Fruit: oranges>,<Fruit: pears>] -> 'apples, oranges and pears'
    """
    if not obj_list:
        return ""
    l=len(obj_list)
    if l==1:
        return u"%s" % obj_list[0]
    else:    
        return ", ".join(unicode(obj) for obj in obj_list[:l-1]) \
                + " and " + unicode(obj_list[l-1])

использовать его в шаблоне: {{ fruits | join_with_commas }}

Если вы хотите '.- в конце ответа Майкла Мэтью Тумима используйте:

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}

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

from django import template


register = template.Library()


@register.filter
def join_and(value):
    """Given a list of strings, format them with commas and spaces, but
    with 'and' at the end.

    >>> join_and(['apples', 'oranges', 'pears'])
    "apples, oranges, and pears"

    """
    # convert numbers to strings
    value = [str(item) for item in value]

    if len(value) == 1:
        return value[0]

    # join all but the last element
    all_but_last = ", ".join(value[:-1])
    return "%s, and %s" % (all_but_last, value[-1])

однако, если вы хотите иметь дело с чем-то более сложным, чем просто списки строк, вам придется использовать явный {% for x in y %} цикл в вашем шаблоне.

Если вам нравятся однострочные:

@register.filter
def lineup(ls): return ', '.join(ls[:-1])+' and '+ls[-1] if len(ls)>1 else ls[0]

а затем в шаблоне:

{{ fruits|lineup }}

Я бы просто использовать ', '.join(['apples', 'oranges', 'pears']) перед отправкой в шаблон в качестве контекстных данных.

обновление:

data = ['apples', 'oranges', 'pears']
print(', '.join(data[0:-1]) + ' and ' + data[-1])

вы получаете apples, oranges and pears выход.