2009-08-06 6 views
54

fruits Если список ['apples', 'oranges', 'pears'],разделенных запятыми списки в шаблонах Джанго

есть быстрый способ использования Джанго теги шаблонов для создания «яблоки, апельсины, груши и»?

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

В качестве продолжения мои попытки сбросить Oxford Comma (то есть вернуть «яблоки, апельсины и груши») даже более беспорядочно.

+2

Почему вы не используете существующий тег шаблона соединения? –

+1

@ S.Lott: Я не заметил тег шаблона соединения, когда просматривал список на странице документов. К сожалению. Сказав это, следующий этап - обернуть каждый элемент в списке гиперссылкой, для которой, я думаю, мне нужно будет написать фильтр. – Alasdair

+0

Если вы используете ссылки на URL-адрес Django, вам нужно использовать тег '{% url%}. Цикл '{% for%}' неожиданно выглядит гораздо более привлекательным. «Неоднократно» часто означает, что ваши шаблоны должны иметь '{% include%}' общие функции. –

ответ

30

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

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

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

+0

Мне не было известно о различии между тегами и фильтрами. В то время как пользовательские теги кажутся немного сложными, когда я смотрю на документацию, фильтры кажутся более простыми и именно то, что мне нужно в этом случае. Благодаря! – Alasdair

+5

Это не вставляет окончательные «и». – Meekohi

+1

@Meekohi, поэтому 'return arg.join (значение [: - 1]) + 'и' + значение [-1]' (для стиля AP, то есть без запятой до 'and', для стиля« Оксфордская запятая », добавьте '+ arg' прямо перед' + 'и''). Я, я предпочитаю силу асиндетона, по http://literarydevices.net/asyndeton/. И ни одна из этих прекрасных дебатов по английскому стилю в любом случае не относится к StackOverflow - возьмите это на english.stackexchange.com!) –

111

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

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

Вот их пример

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

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

fruits_text = ", ".join(fruits) 

Обеспечение fruits_text в шаблон для рендеринга.

+0

Мне могут потребоваться другие списки (например, 'vegetables_text'), и я могу использовать эти списки во множестве просмотров, поэтому я предпочел бы иметь решение, требующее только изменения шаблонов. Одной из причин, по которой я думал о написании пользовательского тега, является то, что я могу использовать Python - 'join' определенно более элегантен, чем для циклов. – Alasdair

+4

Это также не вставляет окончательные «и». – Meekohi

+0

Есть ли какие-либо рекомендации относительно того, делать это в шаблоне или в представлении? – Rikki

6

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

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

59

Вот супер простое решение. Поместите этот код в comma.html:

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

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

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

Очень полезно. Благодаря! –

+3

лучшее решение, если вам нужно присоединиться больше, чем строки в массиве – BiAiB

+0

Очень умное решение. – vmassuchetto

4

Если вы хотите на конце ответа Майкла Мэтью Toomim, а затем использовать:

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

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

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 %} цикл в шаблоне.

0

Если вы хотите остроты:

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

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

{{ fruits|lineup }} 
13

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

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

Очень чистое и простое решение. – SaeX