如果fruits是清单['apples', 'oranges', 'pears'],
有没有一种使用Django模板标签生成“苹果,橘子和梨”的快速方法?
我知道使用循环和{% if counter.last %}语句执行此操作并不难,但是由于我将反复使用它,所以我认为我将必须学习如何编写自定义标签 过滤器,如果已经完成,我不想重新发明轮子。
作为扩展,我尝试删除牛津逗号(即返回“苹果,橘子和梨”)的操作更加混乱。
如果fruits是清单['apples', 'oranges', 'pears'],
有没有一种使用Django模板标签生成“苹果,橘子和梨”的快速方法?
我知道使用循环和{% if counter.last %}语句执行此操作并不难,但是由于我将反复使用它,所以我认为我将必须学习如何编写自定义标签 过滤器,如果已经完成,我不想重新发明轮子。
作为扩展,我尝试删除牛津逗号(即返回“苹果,橘子和梨”)的操作更加混乱。
{% url %}标记。该{% for %}回路突然看起来更吸引人。“重复”通常意味着您的模板需要{% include %}通用功能。
                Answers:
首选:使用现有的联接模板标记。
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#join
这是他们的例子
{{ value|join:" // " }}
第二选择:在视图中进行操作。
fruits_text = ", ".join( fruits )
提供fruits_text给模板进行渲染。
vegetables_text),并且可能在很多视图中使用这些列表,所以我宁愿有一个只需要更改模板的解决方案。我考虑编写自定义标签的原因之一是我可以使用Python-join绝对比for循环更优雅。
                    这是一个超级简单的解决方案。将此代码放入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 %}
更新:@ user3748764为我们提供了一个更紧凑的版本,没有不赞成使用的ifequal语法:
{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}
请注意,应在元素之前而不是之后使用它。
{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}请注意,应在元素之前而不是之后使用它。
                    我建议使用自定义django模板过滤器,而不是自定义标签-过滤器更方便,更简单(在适当的地方,例如这里)。{{ fruits | joinby:", " }}看起来像我想要的...使用自定义joinby过滤器:
def joinby(value, arg):
    return arg.join(value)
如您所见,这本身就是简单性!
return arg.join(value[:-1]) + ' and ' + value[-1](对于AP样式,即,之前没有逗号and;对于“ Oxford逗号”样式,请+ arg在“ +”和“`”之前添加一个权利)。我,我更喜欢asyndeton的力量,请参阅literarydevices.net/asyndeton。无论如何,关于英语风格的这场激烈辩论都没有落在StackOverflow上–将其转到english.stackexchange.com!-)
                    'and'代码在上面的注释中编码为无条件插入'and'。在很短的时间内表现不同所需要做的value就是编写代码[[as above] if len(value)>1 else value。BTW asyndeton具有很高的可读性-亚里斯多德,莎士比亚,乔伊斯(当然还有很多人)都有效地使用了它,而我对它的偏爱首先源于我是诗人。
                    这是我为解决问题而写的过滤器(不包括牛津逗号)
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 }}
此处的所有答案均不满足以下一项或多项要求:
and用于最后一项。这是我进入该经典的内容。一,测试:
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 }}
我会', '.join(['apples', 'oranges', 'pears'])在将其作为上下文数据发送到模板之前简单地使用。
更新:
data = ['apples', 'oranges', 'pears']
print(', '.join(data[0:-1]) + ' and ' + data[-1])
您将获得apples, oranges and pears输出。
"apples, oranges, pears"。所需的输出是"apples, oranges, and pears"。
                    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 %}在模板中使用显式循环。