views:

118

answers:

2

I feel like I am writing something that should already exist.

Does Django have a template filter that joins a list of items on commas and places and 'and' before the last one?

For example:

a = ['foo',]
b = ['bar', 'baz',]
c = a + b
d = c + ['yourmom',]

The filter I am looking for would display each list in the following ways:

a would display 'foo'.
b would display'bar and baz'.
c would display 'foo, bar, and baz'.
d would display 'foo, bar, baz, and yourmom'.

QUESTION 1: Is there something that does that already?


I tried to write this myself and it is breaking in two places:

My code: http://pastie.org/private/fhtvg5tchtwlnrdyuoyeja

QUESTION 2: It breaks on forloop.counter & tc.author.all|length. Please explain why these are not valid.

A: 

Try a filter like this (not tested):

def human_join(values):
    out = ', '.join(values[:-1])
    if out:
        out += ' and '

    if values:
        out += values[-1]

    return out
WoLpH
+4  A: 

You can do it in your template:

{% for item in list %}
    {% if forloop.first %}{% else %}
        {% if forloop.last %} and {% else %}, {% endif %}
    {% endif %}{{item}}
{% endfor %}


line breaks added for clarity: remove them in order to avoid unwanted blank spaces in your output:

{% for item in list %}{% if forloop.first %}{% else %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}{{item}}{% endfor %}


Edit: Changed code. Thanks to Eric Fortin for making me notice that I was confused.

dolma33
Actually, I think it needs to be reversed like so:{% if forloop.last %} and {% else %}, {% endif %}{{item}} and we also need a first if to check for first element to avoid displaying "foo and" for the first example.So: {% if forloop.first %}{{item}}{% else %}{% if forloop.last %} and {% else %}, {% endif %}{{item}}{% endif %}
Eric Fortin
Thanks for posting. I feel lame. I think I over thought it.
jakopanda