Jinja2 模板 — 渲染 HTML 页面
本章你将学会用 Jinja2 模板引擎渲染完整的 HTML 页面,抽取公共布局。
从字符串到模板
上一章视图函数直接返回字符串,里行嵌 HTML 标签,无法复用、难以维护。
render_template() 是 Flask 渲染模板的入口:它加载 HTML 文件、注入变量、返回完整的 HTML 响应。
实例
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
# render_template('模板文件名', 变量名=值, ...)
return render_template('index.html', title='RUNOOB 博客')
Flask 默认在项目根目录的 templates/ 文件夹中查找模板。
创建模板文件
在项目根目录下创建 templates/ 文件夹,然后创建 index.html。
实例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>欢迎光临,这是用 Jinja2 模板引擎渲染的页面。</p>
</body>
</html>
Jinja2 模板语法速览
Jinja2 语法与 Django 模板语法几乎完全一样,也与 Vue3 的插值语法类似。
| 用途 | Jinja2 / Django | 说明 |
|---|---|---|
| 输出变量 | {{ variable }} | 支持属性访问:{{ user.name }} |
| 循环 | {% for item in list %}...{% endfor %} | 支持 loop.index |
| 条件 | {% if cond %}...{% endif %} | 可链式:{% elif %} |
| 继承 | {% extends 'base.html' %} | 必须在第一行 |
| 块定义 | {% block name %}...{% endblock %} | 子模板填充父模板的空位 |
Jinja2 和 Django 模板的语法几乎一致,但 Jinja2 更灵活:你可以在模板中写更复杂的 Python 表达式,Django 模板则故意限制了一些能力以避免业务逻辑泄漏到模板中。
模板继承:base.html
多个页面共享导航栏、页脚,用 模板继承 避免重复 HTML。
创建 base.html 父模板
实例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- block title:子模板可以覆盖页面标题 -->
<title>{% block title %}RUNOOB 博客{% endblock %}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
color: #333;
}
.navbar {
display: flex; justify-content: space-between; align-items: center;
padding: 16px 40px; background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.navbar .logo { font-size: 22px; font-weight: bold; color: #e74c3c; text-decoration: none; }
.navbar a { margin-left: 20px; text-decoration: none; color: #333; }
.container { max-width: 960px; margin: 40px auto; padding: 0 20px; }
.footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }
</style>
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">RUNOOB 博客(Flask)</a>
<nav>
<a href="/">首页</a>
<a href="/about">关于</a>
</nav>
</header>
<main class="container">
<!-- block content:子模板在此处填入页面主体内容 -->
{% block content %}
{% endblock %}
</main>
<footer class="footer">
<p>© 2024 RUNOOB 博客. Powered by Flask.</p>
</footer>
</body>
</html>
子模板继承父模板
实例
{% extends 'base.html' %}
{% block title %}RUNOOB 博客 - 首页{% endblock %}
{% block content %}
<h2>最新文章</h2>
<p>文章列表将在后续章节展示。</p>
{% endblock %}
{% extends 'base.html' %}必须写在子模板的第一行(注释除外)。这是 Jinja2 的硬性要求——模板引擎需要最先确定继承关系。
url_for() 生成链接
不要硬编码 URL,用 url_for() 通过函数名反查地址。
实例
@app.route("/")
def index(): ...
@app.route("/post/<int:post_id>")
def post_detail(post_id): ...
路由变了(如 /post/ 改成 /article/),模板中的 url_for() 自动生成新地址。
静态文件配置
Flask 默认将 static/ 目录作为静态文件根目录。
blog_project/ ├── static/ │ ├── css/ │ │ └── style.css │ ├── js/ │ │ └── main.js │ └── images/ │ └── logo.png ├── templates/ └── app.py
模板中通过 url_for('static', filename='css/style.css') 引用。
本章小结
本章你掌握了 Jinja2 模板的核心:render_template() 渲染模板、{{ }} 输出变量、{% for/if %} 控制流、base.html + block + extends 模板继承、url_for() 生成链接。
现在博客页面变成了结构清晰的 HTML,公共部分抽取到了 base.html 中。

[/mycode4]