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 theemployees
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.
- Bracket Notation:
- 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 thedetails
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 dotdetails.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 accessesdetails['department']
.key_name_literal
is a variable defined within Jinja using{% set ... %}
.details[key_name_literal]
correctly accessesdetails['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 forkey_name
if it exists, otherwise returnsdefault_value
. If no default is provided, it returns nothing (effectivelyNone
).
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 notationmy_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.