jinja
python
template
comma delimited
string formatting

How to output a comma delimited list in jinja python template?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The simplest way to output a comma-delimited list in Jinja is to use the join filter. It is shorter, clearer, and less error-prone than manually writing a loop with comma logic unless you need per-item formatting that join cannot express directly.

The Straightforward Solution: join

If your template variable is already a list of strings, use:

jinja
{{ items | join(', ') }}

Example Python context:

python
items = ["apples", "bananas", "cherries"]

Rendered output:

text
apples, bananas, cherries

This is the normal Jinja answer for a comma-separated list.

Example in a Flask View

Here is a tiny Flask example showing the data flow end to end:

python
1from flask import Flask, render_template_string
2
3app = Flask(__name__)
4
5@app.get("/")
6def index():
7    items = ["red", "green", "blue"]
8    template = "{{ items | join(', ') }}"
9    return render_template_string(template, items=items)

The template stays clean because Jinja handles the delimiter insertion for you.

Lists of Objects

If the list contains objects rather than plain strings, map the attribute first and then join:

jinja
{{ users | map(attribute='name') | join(', ') }}

For example, with Python data like:

python
1users = [
2    {"name": "Ava"},
3    {"name": "Noah"},
4    {"name": "Mia"},
5]

The template renders:

text
Ava, Noah, Mia

This is usually better than pushing formatting logic back into Python just to create a display string.

When a Manual Loop Is Useful

Sometimes you need to wrap each item in markup or apply conditional formatting. In that case, a loop plus loop.last is appropriate:

jinja
{% for item in items %}
  <span>{{ item }}</span>{% if not loop.last %}, {% endif %}
{% endfor %}

This is more verbose than join, but it gives you control over each rendered element.

Empty Lists and Missing Values

join behaves well with empty lists:

jinja
{{ items | join(', ') }}

If items is empty, the output is just an empty string. That is often exactly what you want.

If items may be None, guard it:

jinja
{{ (items or []) | join(', ') }}

That prevents template errors when the view context is missing the expected list value.

Escaping and HTML Output

When autoescaping is enabled, Jinja still escapes each item before output unless you explicitly mark content safe. That means:

python
items = ["<b>one</b>", "<script>alert(1)</script>"]

rendered through:

jinja
{{ items | join(', ') }}

will be escaped in HTML contexts. This is normally the correct behavior. Do not use safe unless you truly trust the content.

Keep the Formatting Rule in One Place

If you render the same comma-delimited list in multiple templates, consider pushing a prepared display list from Python or creating a macro if the rendering needs become more complex. For simple cases, though, join is already the right abstraction.

A good rule is:

  • use join for plain strings or straightforward attribute extraction
  • use a loop only when each element needs custom markup or conditional behavior

Common Pitfalls

The biggest mistake is manually managing commas in a loop when join would do the job more cleanly. Manual comma logic is easy to get wrong, especially around the last element.

Another issue is trying to join non-string objects without first extracting or converting the relevant field. If the objects are dictionaries or model instances, map the desired attribute before joining.

Finally, be careful with HTML safety. A comma-delimited list is still template output, so normal escaping rules still matter. Do not mark the whole result safe unless the underlying content is trusted.

Summary

  • Use {{ items | join(', ') }} for the standard comma-delimited case.
  • For lists of objects, map the desired attribute before joining.
  • Use loop.last only when you need custom per-item markup.
  • Guard against None with (items or []) when needed.
  • Let Jinja keep autoescaping on unless you explicitly trust the content.

Course illustration
Course illustration