逗号分隔django模板中的列表

时间:2009-08-06 01:50:18

标签: python django list django-templates

如果fruits是列表['apples', 'oranges', 'pears']

使用django模板标签快速生成“苹果,橘子和梨”吗?

我知道使用循环和{% if counter.last %}语句执行此操作并不困难,但因为我将反复使用它,我想我将不得不学习如何编写自定义标记过滤器,如果已经完成,我不想重新发明轮子。

作为扩展,我试图放弃Oxford Comma(即返回“苹果,橘子和梨”)甚至更加混乱。

11 个答案:

答案 0 :(得分:126)

首选:使用现有的连接模板标记。

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

这是他们的例子

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

第二选择:在视图中执行。

fruits_text = ", ".join( fruits )

为模板提供fruits_text以进行渲染。

答案 1 :(得分:63)

这是一个超级简单的解决方案。将此代码放入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 %}

答案 2 :(得分:34)

我建议自定义django模板过滤器而不是自定义标记 - 过滤器更方便,更简单(在适当的地方,就像这里一样)。 {{ fruits | joinby:", " }}看起来就像我想要的那样...使用自定义joinby过滤器:

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

正如你所看到的那样简单!

答案 3 :(得分:21)

在Django模板上,您需要做的就是在每个水果之后建立一个逗号。一旦它到达最后一个果实,逗号就会停止。

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

答案 4 :(得分:7)

这是我为解决我的问题所写的过滤器(它不包括牛津逗号)

def join_with_commas(obj_list):
    """Takes a list of objects and returns their string representations,
    separated 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(str(obj) for obj in obj_list[:l-1]) \
                + " and " + str(obj_list[l-1])

要在模板中使用它:{{ fruits|join_with_commas }}

答案 5 :(得分:4)

如果你想要一个'。'在Michael Matthew Toomim的回答结束时,然后使用:

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

答案 6 :(得分:2)

此处的所有答案均无法通过以下一项或多项操作:

  • 他们重写标准模板库中的内容(可怜!)(糟糕,最重要的答案!)
  • 最后一项不使用and
  • 他们没有连续的(牛津)逗号。
  • 它们使用负索引,不适用于Django查询集。
  • 他们通常无法正确处理字符串卫生。

这是我进入该经典的时间。首先,测试:

class TestTextFilters(TestCase):

    def test_oxford_zero_items(self):
        self.assertEqual(oxford_comma([]), '')

    def test_oxford_one_item(self):
        self.assertEqual(oxford_comma(['a']), 'a')

    def test_oxford_two_items(self):
        self.assertEqual(oxford_comma(['a', 'b']), 'a and b')

    def test_oxford_three_items(self):
        self.assertEqual(oxford_comma(['a', 'b', 'c']), 'a, b, and c')

现在是代码。是的,它有点混乱,但是您会发现它使用负索引:

from django.utils.encoding import force_text
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe

@register.filter(is_safe=True, needs_autoescape=True)
def oxford_comma(l, autoescape=True):
    """Join together items in a list, separating them with commas or ', and'"""
    l = map(force_text, l)
    if autoescape:
        l = map(conditional_escape, l)

    num_items = len(l)
    if num_items == 0:
        s = ''
    elif num_items == 1:
        s = l[0]
    elif num_items == 2:
        s = l[0] + ' and ' + l[1]
    elif num_items > 2:
        for i, item in enumerate(l):
            if i == 0:
                # First item
                s = item
            elif i == (num_items - 1):
                # Last item.
                s += ', and ' + item
            else:
                # Items in the middle
                s += ', ' + item

    return mark_safe(s)

您可以在django模板中使用以下命令:

{% load my_filters %}
{{ items|oxford_comma }}

答案 7 :(得分:1)

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 %}循环。

答案 8 :(得分:1)

在将import { decorate, observable } from 'mobx' import { serializable, primitive } from 'serializr' import persist from 'mobx-persist'; class Todo { id = Math.random(); title = ""; finished = false; } decorate(Todo, { title: [serializable(primitive), persist('object'), observable], finished: observable }) 作为上下文数据发送到模板之前,我会简单地使用它。

更新:

', '.join(['apples', 'oranges', 'pears'])

您将获得data = ['apples', 'oranges', 'pears'] print(', '.join(data[0:-1]) + ' and ' + data[-1]) 的输出。

答案 9 :(得分:0)

如果你喜欢单行:

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

然后在模板中:

{{ fruits|lineup }}

答案 10 :(得分:0)

我认为最简单的解决方案可能是:

@register.filter
def comma_list(p_values: Iterable[str]) -> List[str]:
    values = list(p_values)
    if len(values) > 1:
        values[-1] = u'and %s' % values[-1]
    if len(values) > 2:
        return u', '.join(values)
    return u' '.join(values)