Pass data to templates through the rendering context.
Basic Rendering
Pass variables as keyword arguments:
template = env.get_template("page.html")
html = template.render(
title="My Page",
user=current_user,
items=item_list,
)
Or as a dictionary:
context = {
"title": "My Page",
"user": current_user,
"items": item_list,
}
html = template.render(context)
Convenience Methods
Environment provides shortcuts:
# Combines get_template() + render()
html = env.render("page.html", title="Hello")
# Combines from_string() + render()
html = env.render_string("{{ x * 2 }}", x=21)
Global Variables
Variables available in all templates:
env = Environment(loader=FileSystemLoader("templates/"))
# Add globals
env.add_global("site_name", "My Site")
env.add_global("current_year", 2024)
env.add_global("format_date", format_date_func)
Access in templates:
<title>{{ site_name }}</title>
<footer>© {{ current_year }}</footer>
{{ format_date(post.date) }}
Built-in Globals
Kida includes common Python builtins:
{{ range(10) }}
{{ len(items) }}
{{ dict(a=1, b=2) }}
{{ max(scores) }}
Available:range,dict,list,set,tuple,len,str,int,float,bool,abs,min,max,sum,sorted,reversed,enumerate,zip,map,filter.
Object Access
Templates access object attributes:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
template.render(user=User("Alice", "alice@example.com"))
{{ user.name }}
{{ user.email }}
Dictionary Access
template.render(config={"timeout": 30, "retries": 3})
{{ config.timeout }}
{{ config["timeout"] }}
Nested Contexts
Build complex nested data:
template.render(
site={
"title": "My Site",
"nav": [
{"title": "Home", "url": "/"},
{"title": "About", "url": "/about"},
],
},
page={
"title": "Welcome",
"content": "Hello, world!",
},
)
<title>{{ page.title }} - {{ site.title }}</title>
<nav>
{% for item in site.nav %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% end %}
</nav>
Undefined Variables
By default, undefined variables raise errors:
template = env.from_string("{{ missing }}")
template.render() # Raises UndefinedError
Usedefaultfilter for optional values:
{{ user.nickname | default("Anonymous") }}
{{ config.timeout | default(30) }}
Context Isolation
Eachrender()call starts with a fresh context:
# These don't affect each other
html1 = template.render(x=1)
html2 = template.render(x=2)
Globals are shared but render context is isolated.
Best Practices
Keep Context Flat
# ✅ Flat, easy to access
template.render(
title=page.title,
user=current_user,
items=items,
)
# ❌ Deeply nested
template.render(
data={
"page": {"meta": {"title": ...}},
...
}
)
Use Typed Objects
# ✅ IDE support, validation
@dataclass
class PageContext:
title: str
user: User
items: list[Item]
template.render(**asdict(PageContext(...)))
Precompute in Python
# ✅ Python handles complexity
template.render(
formatted_items=[format_item(i) for i in items],
total=sum(i.price for i in items),
)
# ❌ Complex logic in template
# {% set total = 0 %}
# {% for item in items %}{% set total = total + item.price %}{% end %}
See Also
- Escaping — HTML escaping
- Custom Globals — Add global functions
- API Reference — Environment.render()