Skip to main content

How to Iterate Over Dictionaries and Lists of Dictionaries in Jinja template in Python

Web frameworks like Flask and Django often use Jinja2 as their templating engine to dynamically generate HTML. A common requirement is to display data passed from the Python backend, frequently structured as dictionaries or lists containing dictionaries. Jinja provides intuitive control structures, similar to Python's, for looping through these data structures.

This guide demonstrates how to effectively iterate over single dictionaries and lists of dictionaries within your Jinja templates, accessing both keys and values.

Setup: Passing Data from Python to Jinja

Assumption: Your project has a structure like this:

my_project/
├── main.py # Your Python script (e.g., Flask app)
└── templates/
└── home.html # Your Jinja template file

Before you can iterate in Jinja, you need to pass the dictionary or list from your Python code to the template during the rendering process.

# main.py (Example Setup)
from jinja2 import Environment, FileSystemLoader
import os

# Sample Data
employee_list = [
{"id": 101, "name": "Alice", "role": "Developer"},
{"id": 102, "name": "Bob", "role": "Designer"},
{"id": 103, "name": "Charlie", "role": "Manager"},
]

employee_details = {
"employee_id": 205,
"full_name": "David Lee",
"department": "Engineering",
"years": 3
}

key_to_access = "department" # Example key stored in a variable

# Jinja Environment Setup
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
env = Environment(loader=FileSystemLoader(template_dir))
template = env.get_template('home.html')

# Render the template, passing data as keyword arguments
# The keys here ('employees', 'details', 'dynamic_key') become variable names in Jinja
output_html = template.render(
employees=employee_list,
details=employee_details,
dynamic_key=key_to_access
)

print(output_html) # Or return this in a web framework response

The keys used when calling template.render() (employees, details, dynamic_key) are the variable names you will use within the home.html template.

Iterating Over a List of Dictionaries

This is common for displaying tables or lists of items (users, products, etc.).

Dynamic Iteration (Using .items())

If you want to display all key-value pairs for each dictionary in the list without knowing the keys beforehand:

<!-- templates/home.html -->
<h3>Employee List (Dynamic Iteration):</h3>
{% for employee_dict in employees %}
<div style="border: 1px solid #ccc; margin-bottom: 10px; padding: 5px;">
<h4>Employee Record:</h4>
<ul>
{% for key, value in employee_dict.items() %}
<li><strong>{{ key }}:</strong> {{ value }}</li>
{% endfor %}
</ul>
</div>
{% else %}
<p>No employees found.</p>
{% endfor %}
  • The outer {% for employee_dict in employees %} loop iterates through the list passed from Python.
  • The inner {% for key, value in employee_dict.items() %} loop iterates through the key-value pairs of the current dictionary (employee_dict) in the outer loop. dict.items() works just like in Python.
  • {{ key }} and {{ value }} display the current key and value.
  • The {% else %} block within the outer loop is optional and renders if the employees list is empty.

Partial Rendered Output Example for Dynamic Iteration:

    <div style="border: 1px solid #ccc; margin-bottom: 10px; padding: 5px;">
<h4>Employee Record:</h4>
<ul>
<li><strong>id:</strong> 101</li>
<li><strong>name:</strong> Alice</li>
<li><strong>role:</strong> Developer</li>
</ul>
</div>
<div style="border: 1px solid #ccc; margin-bottom: 10px; padding: 5px;">
<h4>Employee Record:</h4>
<ul>
<li><strong>id:</strong> 102</li>
<li><strong>name:</strong> Bob</li>
<li><strong>role:</strong> Designer</li>
</ul>
</div>
<!-- ... more employees ... -->

Accessing Specific Known Keys

More often, you know the exact keys you want to display for each dictionary in the list.

<!-- templates/home.html -->
<h3>Employee List (Specific Keys):</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{% for emp in employees %}
<tr>
<td>{{ emp['id'] }}</td> <!-- Bracket Notation -->
<td>{{ emp.name }}</td> <!-- Dot Notation (often works) -->
<td>{{ emp.role | title }}</td> <!-- Example with a filter -->
</tr>
{% else %}
<tr>
<td colspan="3">No employees found.</td>
</tr>
{% endfor %}
</tbody>
</table>
  • The outer {% for emp in employees %} loop iterates through the list.
  • Inside the loop, you access values using either:
    • Bracket Notation: emp['key_name'] (e.g., emp['id']). This is similar to Python dictionary access.
    • Dot Notation: emp.key_name (e.g., emp.name). Jinja often allows this as a shortcut if the key is a valid identifier (no spaces, special chars, etc.). It's generally less robust than bracket notation if keys vary.
  • You can apply Jinja filters (like | title) to the values.

Rendered Output Example for Specific Keys:

<h3>Employee List (Specific Keys):</h3>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>101</td>
<td>Alice</td>
<td>Developer</td>
</tr>
<tr>
<td>102</td>
<td>Bob</td>
<td>Designer</td>
</tr>
<tr>
<td>103</td>
<td>Charlie</td>
<td>Manager</td>
</tr>
</tbody>
</table>

Iterating Over a Single Dictionary

If you pass a single dictionary to your template.

Using .items()

To loop through all key-value pairs of a single dictionary:

<!-- templates/home.html -->
<h3>Single Employee Details (Dynamic):</h3>
<ul>
{% for data_key, data_value in details.items() %}
<li><i>{{ data_key }}:</i> {{ data_value }}</li>
{% else %}
<li>Dictionary is empty.</li>
{% endfor %}
</ul>
  • {% for data_key, data_value in details.items() %} iterates directly over the key-value pairs of the details dictionary passed from Python.

Rendered Output Example:

<h3>Single Employee Details (Dynamic):</h3>
<ul>
<li><i>employee_id:</i> 205</li>
<li><i>full_name:</i> David Lee</li>
<li><i>department:</i> Engineering</li>
<li><i>years:</i> 3</li>
</ul>

Accessing Specific Known Keys

If you just need specific values from the dictionary:

<!-- templates/home.html -->
<h3>Single Employee Details (Specific):</h3>
<p>Name: {{ details['full_name'] }}</p> <!-- Bracket -->
<p>Department: {{ details.department }}</p> <!-- Dot -->
<p>Years of Service: {{ details['years'] }}</p>
  • Use bracket details['key'] or dot details.key notation.

Rendered Output Example:

<h3>Single Employee Details (Specific):</h3>
<p>Name: David Lee</p>
<p>Department: Engineering</p>
<p>Years of Service: 3</p>

Accessing Keys Using Variables

If the name of the key you want to access is stored in another Jinja variable, you must use bracket notation. Dot notation will not work.

<!-- templates/home.html -->
{% set key_name_literal = 'full_name' %}

<h3>Accessing via Variables:</h3>
<p>Accessing '{{ dynamic_key }}': {{ details[dynamic_key] }}</p> <!-- dynamic_key is 'department' from Python -->
<p>Accessing '{{ key_name_literal }}': {{ details[key_name_literal] }}</p>

<!-- This would NOT work: {{ details.dynamic_key }} -->
<!-- It would look for a key literally named 'dynamic_key' -->
  • dynamic_key was passed from Python holding the string "department". details[dynamic_key] correctly accesses details['department'].
  • key_name_literal is a variable defined within Jinja using {% set ... %}. details[key_name_literal] correctly accesses details['full_name'].

Rendered Output Example:

<h3>Accessing via Variables:</h3>
<p>Accessing 'department': Engineering</p>
<p>Accessing 'full_name': David Lee</p>

Using dict.get() for Safer Access

Just like in Python, using bracket notation (my_dict['key']) will cause an error if the key doesn't exist. Jinja supports the .get() method for safer access, allowing you to provide a default value.

<!-- templates/home.html -->
<h3>Safer Access with .get():</h3>

<p>Department (get): {{ details.get('department', 'N/A') }}</p>
<p>Manager (get): {{ details.get('manager', 'Not Specified') }}</p> <!-- 'manager' key doesn't exist -->

{% set missing_key_var = 'location' %}
<p>Location (get with var): {{ details.get(missing_key_var, 'Unknown') }}</p>
  • details.get('key_name', default_value): Returns the value for key_name if it exists, otherwise returns default_value. If no default is provided, it returns nothing (effectively None).

Rendered Output Example:

<h3>Safer Access with .get():</h3>

<p>Department (get): Engineering</p>
<p>Manager (get): Not Specified</p>
<p>Location (get with var): Unknown</p>

Conclusion

Jinja provides flexible ways to work with dictionaries and lists passed from your Python application:

  • Use {% for item in my_list %} to loop through lists.
  • Use {% for key, value in my_dict.items() %} to loop through dictionary key-value pairs dynamically.
  • Access specific dictionary values using bracket notation my_dict['key'] or dot notation my_dict.key (for simple keys).
  • When the key name is stored in a variable, only bracket notation my_dict[key_variable] works.
  • Use my_dict.get('key', default) for safe access to potentially missing keys.

Mastering these iteration and access techniques is essential for building dynamic web pages with Jinja.