代码之家  ›  专栏  ›  技术社区  ›  Alasdair

django模板中的逗号分隔列表

  •  60
  • Alasdair  · 技术社区  · 17 年前

    如果 fruits 是名单 ['apples', 'oranges', 'pears'] ,

    有没有一个快速的方法使用django模板标签生产“苹果,桔子和梨”?

    我知道用循环来做这件事并不困难, {% if counter.last %} 语句,但是因为我要重复使用它,我想我必须学习如何编写自定义 标签 过滤器,我不想重新发明轮子,如果它已经完成了。

    作为扩展,我尝试放弃 Oxford Comma (也就是说,“苹果、桔子和梨”)甚至更凌乱。

    10 回复  |  直到 7 年前
        1
  •  124
  •   S.Lott    17 年前

    第一选择:使用现有的连接模板标记。

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

    这是他们的例子

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

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

    fruits_text = ", ".join( fruits )
    

    提供 fruits_text 到模板进行渲染。

        2
  •  62
  •   Michael Matthew Toomim    16 年前

    这是一个非常简单的解决方案。将此代码放入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 %}
    
        3
  •  33
  •   Alex Martelli    17 年前

    我建议你定制一个Django模板 滤波器 而不是一种习俗 标签 --过滤器更方便、更简单(在适当的地方,如这里)。 {{ fruits | joinby:", " }} 看起来像是我想要的…有习俗 joinby 过滤器:

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

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

        4
  •  18
  •   theB    10 年前

    在django模板上,您只需在每个水果后建立一个逗号。逗号一到最后一个水果就停止。

    {% if not forloop.last %}, {% endif %}
    
        5
  •  7
  •   Alasdair    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 }}

        6
  •  4
  •   Todd Davies    13 年前

    如果你想要一个“.”,在Michael Matthew Toomim答案的末尾,那么使用:

    {% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}
    
        7
  •  2
  •   mlissner    7 年前

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

    • 他们重写了一些东西(糟糕!)在标准模板库中(ack,top answer!)
    • 他们不使用 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 }}
    
        8
  •  1
  •   Wilfred Hughes AntuanSoft    13 年前

    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 %} 在模板中循环。

        9
  •  0
  •   Tunaki    10 年前

    如果你喜欢一句话:

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

    然后在模板中:

    {{ fruits|lineup }}
    
        10
  •  0
  •   Yiğit Genç    8 年前

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

    更新:

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

    你会得到 apples, oranges and pears 输出。