Files
Vinta ChenandClaude a04833275a docs: rewrite Template Engines category intro lead
This lead followed the same appositive frame as the other category intro leads ("X, a/the Python Y library ..."), so it read as one template with the category swapped in; it now has its own sentence frame, keeping the same picks and facts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-27 14:53:14 +08:00

2.7 KiB

Whether templates may hold Python code splits the Python template engines: Jinja keeps code out and sandboxes untrusted templates, Mako embeds plain Python.

How to choose:

  • Templates without embedded Python: Jinja
  • Templates your users write: Jinja, in its sandbox
  • Plain Python inside your templates: Mako

Jinja doesn't allow arbitrary Python code in templates: you get blocks, filters, and function calls, and the rest of your logic stays in Python. Outside a framework, create one Environment when your app starts and load templates through a PackageLoader. Put the layout your pages share in a base template, and let each page extend it and override its blocks. Flask sets up Jinja for you, Django has a built-in Jinja2 backend, and FastAPI supports it with Jinja2Templates.

When your users write templates, like a report layout, render them in Jinja's sandbox, which can block attribute access, method calls, and other operations. Its docs say the sandbox alone is not a solution for perfect security: catch errors when a template renders, limit CPU and memory, and pass the template only the data it needs.

Mako is an embedded Python language: inside <% %> tags you write regular Python. A real application loads its templates from a TemplateLookup with a module_directory, which caches each compiled template on disk as a Python module.

Jinja leaves HTML escaping off by default, since it also renders plain text, emails, and config files. When you create the Environment yourself, turn it on with select_autoescape(); Flask turns it on for HTML templates, and Django's Jinja2 backend turns it on for all. Mako escapes HTML only through the h filter: add it to default_filters on your TemplateLookup to escape every expression.