Jinja 模板引擎实战指南(Python)
Jinja2 是 Python 模板引擎:变量、控制结构、模板继承、宏与过滤器。本文结合 Flask 应用实战,讲清 Jinja 的核心概念与进阶用法。
直接回答:Jinja2 是 Python 生态的事实标准模板引擎——Flask、Ansible、SaltStack、Sphinx 都在用。语法简洁但功能完备:继承、宏、过滤器、测试器一应俱全,平衡了简单与强大。
Jinja 的生态位
出自 Flask 作者 Armin Ronacher 之手,灵感来自 Django 模板但表达力更强。如今它的身影遍布:Web 框架(Flask)、配置管理(Ansible playbook)、静态站点生成、文档系统、邮件与报表模板。学会一处,处处受用。
安装与最小用法
pip install jinja2
from jinja2 import Environment, FileSystemLoader, select_autoescape
env = Environment(loader=FileSystemLoader("templates"),
autoescape=select_autoescape(["html", "htm", "xml"]))
tpl = env.get_template("hello.html")
print(tpl.render(name="世界"))
Flask 中无需配置——render_template("page.html", ...) 直接可用。
核心语法
<h1>{{ title }}</h1> <!-- 变量插值(自动转义) -->
{% if user.is_admin %}
<a href="/admin">管理后台</a>
{% endif %}
<ul>
{% for item in items %}
<li>{{ loop.index }}. {{ item.name }}</li> <!-- loop 内置计数 -->
{% else %}
<li>暂无数据</li>
{% endfor %}
</ul>
模板继承:布局复用的基石
<!-- base.html -->
<html>
<body>
{% block content %}{% endblock %}
</body>
</html>
<!-- page.html -->
{% extends "base.html" %}
{% block content %}
<h2>{{ post.title }}</h2>
<article>{{ post.body }}</article>
{% endblock %}
extends + block 让全站布局只写一遍,子模板只填差异部分。
宏:可复用的模板组件
{% macro render_post(post) %}
<div class="card">
<h3>{{ post.title }}</h3>
<p>{{ post.summary }}</p>
</div>
{% endmacro %}
{{ render_post(p) }}
宏之于模板相当于函数之于代码——列表页、详情页复用同一渲染逻辑。
过滤器与测试器
{{ post.title|upper }} <!-- 大写 -->
{{ price|round(2) }} <!-- 保留两位 -->
{{ items|length }} <!-- 长度 -->
{{ created|datetimeformat("%Y-%m-%d") }} <!-- 自定义过滤器 -->
{{ body|safe }} <!-- 关闭转义(慎用) -->
{{ user.email|default("未填写") }} <!-- 默认值 -->
常用测试:{% if x is defined %}、{% if n is divisibleby(3) %}。内置过滤器覆盖常用转换,剩下的注册自定义过滤器(一个 Python 函数 + env.filters)。
安全须知
- 独立 Jinja Environment 不默认开启自动转义,本文显式配置 select_autoescape;Flask 会对常见 HTML 模板启用——跨站脚本(XSS)防线,别随意用
|safe关闭; - 渲染用户提供的模板代码是危险操作,不应直接信任用户模板。SandboxedEnvironment 只能限制部分操作,仍需最小可见对象、CPU/内存限额、隔离及及时安全更新。
常见问题(FAQ)
Q:Jinja 和 Django 模板怎么选?
A:用 Django 就跟随内置模板(与 Admin/表单联动深);其他场景 Jinja 表达力更强、生态更广。两者语法相似,迁移成本低。
Q:模板里能写复杂逻辑吗?
A:能写不代表该写。模板负责展示,业务逻辑留在视图/服务层。发现自己在模板里写大段 if-else 时,把计算挪回 Python。
Q:Ansible 里的 Jinja 有什么不一样?
A:语法相同但上下文是 Ansible 变量与 facts,且有一堆 Ansible 专属过滤器(to_json、b64encode 等)。踩坑点:YAML 与 Jinja 的花括号冲突需要引号包裹。
官方参考
本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。