Python django模板中的逗号分隔列表

Python django模板中的逗号分隔列表,python,django,list,django-templates,Python,Django,List,Django Templates,如果水果是列表[‘苹果’、‘橘子’、‘梨’] 有没有一种使用django模板标记快速生成“苹果、桔子和梨”的方法 我知道使用循环和{%if counter.last%}语句来实现这一点并不困难,但因为我将反复使用它,我想我将不得不学习如何编写自定义标记过滤器,如果已经完成了,我不想重新发明轮子 作为扩展,我尝试删除(即返回“apples、oranges和pears”)时更加混乱。第一选择:使用现有的join-template标记 这是他们的例子 {{ value|join:" // " }}

如果
水果
是列表
[‘苹果’、‘橘子’、‘梨’]

有没有一种使用django模板标记快速生成“苹果、桔子和梨”的方法

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


作为扩展,我尝试删除(即返回“apples、oranges和pears”)时更加混乱。

第一选择:使用现有的join-template标记

这是他们的例子

{{ value|join:" // " }}
第二种选择:在视图中执行

fruits_text = ", ".join( fruits )

为模板提供
fruits\u text
以进行渲染。

我建议使用自定义django模板过滤器,而不是自定义标记——过滤器更方便、更简单(在适当的情况下,如此处所示)<代码>{{fruits | joinby:“,”}看起来就像我想要的那样。。。使用自定义的
joinby
过滤器:

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

正如你所看到的,这就是简单本身

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

def join_与_逗号(obj_列表):
“”“获取对象列表并返回其字符串表示形式,
用逗号分隔,倒数第二项和最后一项之间用“and”分隔
例如,对于水果对象列表:
[,]->“苹果、桔子和梨”
"""
如果不是obj_列表:
返回“”
l=len(对象列表)
如果l==1:
返回u“%s”%obj_列表[0]
其他:
返回“,”\
+“和”+str(obj_列表[l-1])

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

下面是一个超级简单的解决方案。将此代码放入comma.html:

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}
现在,无论您将逗号放在何处,都应包含“comma.html”:


更新:@user3748764提供了一个稍微紧凑的版本,没有不推荐的ifequal语法:

{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}

请注意,它应该在元素之前使用,而不是之后使用。

如果您想在Michael Matthew Toomim的答案末尾使用“.”,请使用:

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

在Django模板上,这就是在每个水果后建立逗号所需做的全部工作。逗号到达最后一个水果后将停止

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

在将其作为上下文数据发送到模板之前,我只需使用
,'.join(['apples','oranges','pears'])

更新:

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

您将获得苹果、橙子和梨的输出。

此处的所有答案都不符合以下一个或多个条件:

  • 他们重写了标准模板库中的某些内容(很糟糕!)(确认,顶部答案!)
  • 最后一项不使用
  • 它们缺少一个连续的(牛津)逗号
  • 它们使用负索引,这对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 }}

我认为最简单的解决办法可能是:

@register.filter
定义逗号列表(p_值:Iterable[str])->list[str]:
值=列表(p_值)
如果len(值)>1:
值[-1]=u'和%s'%1]值[-1]
如果len(值)>2:
返回u','。连接(值)
返回u“”。连接(值)

我可能需要其他列表(例如
蔬菜\u text
),我可能会在很多视图中使用这些列表,因此我宁愿有一个只需要修改模板的解决方案。我考虑编写自定义标记的原因之一是我可以使用Python-
join
显然比循环更优雅。这也不会插入最后的“and”。在模板或视图中是否有这样做的最佳实践?我不知道标记和过滤器之间的区别。当我查看文档时,自定义标记似乎有点令人生畏,而过滤器似乎更简单,这正是我在本例中需要的。谢谢这不会插入最后的“and”。@Meekohi,因此
返回arg.join(value[:-1])+”和“+value[-1]
(对于AP样式,即在
之前没有逗号;对于“Oxford逗号”样式,在“+”和“`”之前添加一个
+arg
)。我,我更喜欢阿森顿的力量,佩尔。而且,关于英语风格的这场精彩辩论都不属于StackOverflow——请访问English.stackexchange.com!)+1用于返回6年前的问题以回答3年前的评论,但当数组中只有一项时,您的筛选器会做什么?:)使事物具有可读性似乎并不那么容易;插入
和'
的新代码在上述注释中编码为无条件插入
和'
。如果len(value)>1 else值
,那么在很短的时间内行为不同所需要的就是编码
[[如上]并且顺便说一句,asyndeton是高度人类可读的——亚里士多德、莎士比亚、乔伊斯(当然还有许多其他人)所有人都有效地使用了它,我对它的偏爱首先是因为我是一名诗人。你为什么不使用现有的join template标记?@S.Lott:当我在文档页面上查看列表时,我没有发现join template标记。Oops。话虽如此,下一步是将列表中的每个项目包装在一个超链接中,我认为nk我需要写一个过滤器。如果你使用链接到你
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)
{% load my_filters %}
{{ items|oxford_comma }}