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"] }}
Both syntaxes work. For dicts, Kida resolves dot notation to dictionary keys first, so `` is equivalent to config["timeout"]. This means dict key names like items, keys, or values resolve to your data, not the dictmethods:
template.render(section={"items": ["a", "b", "c"], "title": "My Section"})
{% for item in section.items %} {# iterates ["a", "b", "c"], not dict.items() #}
{{ item }}
{% end %}
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
Use defaultfilter 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.
Clean User Context
Your context dictionary remains completely clean—no internal keys are injected:
ctx = {"name": "World", "items": [1, 2, 3]}
template.render(ctx)
# ctx is unchanged after render()
# No _template, _line, _include_depth keys added
assert "_template" not in ctx
Internal state (template name, line number for errors, include depth) is managed via RenderContext ContextVar, not your dictionary. This means you can safely use variable names like _template or _linein your templates:
{{ _template }} {# Works! Your variable, not internal state #}
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()