Comma separated lists in django templates

后端 未结 11 1212
梦如初夏
梦如初夏 2021-01-30 16:00

If fruits is the list [\'apples\', \'oranges\', \'pears\'],

is there a quick way using django template tags to produce \"apples, oranges, and p

相关标签:
11条回答
  • 2021-01-30 16:22

    Django doesn't have support for this out-of-the-box. You can define a custom filter for this:

    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])
    

    However, if you want to deal with something more complex than just lists of strings, you'll have to use an explicit {% for x in y %} loop in your template.

    0 讨论(0)
  • 2021-01-30 16:22

    If you like one-liners:

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

    and then in the template:

    {{ fruits|lineup }}
    
    0 讨论(0)
  • 2021-01-30 16:24

    Here's a super simple solution. Put this code into comma.html:

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

    And now wherever you'd put the comma, include "comma.html" instead:

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

    Update: @user3748764 gives us a slightly more compact version, without the deprecated ifequal syntax:

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

    Note that it should be used before the element, not after.

    0 讨论(0)
  • 2021-01-30 16:29

    Here's the filter I wrote to solve my problem (it doesn't include the Oxford comma)

    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])
    

    To use it in the template: {{ fruits|join_with_commas }}

    0 讨论(0)
  • 2021-01-30 16:35

    I think the simplest solution might be:

    @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)
    
    
    0 讨论(0)
提交回复
热议问题