266

If I have a list of users say ["Sam", "Bob", "Joe"], I want to do something where I can output in my jinja template file:

{% for user in userlist %}
    <a href="/profile/{{ user }}/">{{ user }}</a>
    {% if !loop.last %}
        , 
    {% endif %}
{% endfor %}   

I want to make the output template be:

Sam, Bob, Joe

I tried the above code to check if it was on the last iteration of the loop and if not, then don't insert a comma, but it does not work. How do I do this?

Saeid
  • 4,147
  • 7
  • 27
  • 43
Rolando
  • 58,640
  • 98
  • 266
  • 407

3 Answers3

451

You want your if check to be:

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

Note that you can also shorten the code by using If Expression:

{{ ", " if not loop.last else "" }}
HackDolphin
  • 166
  • 11
Joe Day
  • 6,965
  • 4
  • 25
  • 26
  • 10
    Just fyi, you might need to make this an if/else based on your settings. More info. can be found here: https://github.com/pallets/jinja/issues/710 – Paul Calabro Sep 19 '17 at 23:24
  • 3
    or is some cases `{{ "," if not forloop.last }}` – obotezat Oct 03 '17 at 13:09
  • 9
    I second the comment about adding an else. This worked for me `{{ "," if not loop.last else "" }}` – ahong Jul 05 '19 at 16:00
  • In my case it was `forloop` instead of `loop` and `{%` instead of `{{`, like this: `{% if not forloop.last %},{% endif %}`. Other solutions did not work – P D Oct 14 '20 at 12:46
  • or even shorter: `{{ "" if loop.last else ", " }}` – T.M. Mar 01 '23 at 15:02
280

You could also use the builtin join filter like this:

{{ users|join(', ') }}
Paolo
  • 20,112
  • 21
  • 72
  • 113
Uli Martens
  • 2,901
  • 1
  • 11
  • 4
  • 1
    While this works for creating a csv, seeing his example above, it can't be used with the surrounding anchor. – triunenature Nov 22 '15 at 06:18
  • This approach also doesn't work well with escaping: ['{{ ['a\'', 'b']|join("', '") }}'] produces ['a'', 'b'] – stewbasic Nov 24 '15 at 03:34
  • 11
    This should be the first thing attempted. If it doesn't work as desired, then try another solution, but this is definitely cleanest. – Jerad Jul 22 '17 at 15:40
  • 1
    This gives a trailing comma, how do I get rid of that? – Jonathan Nov 17 '17 at 19:12
  • You probably have an trailing empty element. If you've got three elements a b c you will get aXbXc when joining with X: `ansible -i localhost, all -m debug -a "msg=\"{{ [ 'a','b','c' ]|join('X') }}\""` – Uli Martens Nov 18 '17 at 20:12
  • This doesn't work for IP sets, it'll output much garbage: `"1, 9, 2, ., 1, 6, 8, ., 3, 3, ., 1, 0"` – Daniel Andrei Mincă Dec 19 '17 at 09:34
  • This works if you do not need separate spans/formatting/links on the inner items. – cjm Oct 31 '19 at 03:04
83

And using the joiner from https://jinja.palletsprojects.com/templates/#joiner

{% set comma = joiner(",") %}
{% for user in userlist %}
    {{ comma() }}<a href="/profile/{{ user }}/">{{ user }}</a>
{% endfor %}  

It's made for this exact purpose. Normally a join or a check of forloop.last would suffice for a single list, but for multiple groups of things it's useful.

A more complex example on why you would use it.

{% set pipe = joiner("|") %}
{% if categories %} {{ pipe() }}
    Categories: {{ categories|join(", ") }}
{% endif %}
{% if author %} {{ pipe() }}
    Author: {{ author() }}
{% endif %}
{% if can_edit %} {{ pipe() }}
    <a href="?action=edit">Edit</a>
{% endif %}
HackDolphin
  • 166
  • 11
dalore
  • 5,594
  • 1
  • 36
  • 38