Flask入门教程(九):模板渲染——用Jinja2构建动态页面
2026/8/29 17:53:22 网站建设 项目流程

1. render_template基础

render_template()是Flask中最常用的模板渲染函数。它的第一个参数是模板文件名,后面的关键字参数会作为变量传递给模板。

# 文件路径:app.py from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): return render_template("index.html", title="RUNOOB 首页", name="World") @app.route("/user/<username>") def profile(username): return render_template("user.html", username=username, posts=[ {"title": "Flask 入门", "date": "2026-05-01"}, {"title": "Jinja2 模板", "date": "2026-05-10"}, ])

模板文件放在项目目录下的templates/文件夹中:

runoob-flask-test/ ├── app.py └── templates/ ├── index.html └── user.html

templates/index.html:

<!DOCTYPE html> <html> <head> <title>{{ title }} - RUNOOB</title> </head> <body> <h1>{{ title }}</h1> <p>Hello {{ name }}。</p> </body> </html>

2. Jinja2基础语法

Jinja2模板中三种核心语法:

语法用途示例
{{ ... }}输出变量值,自动转义HTML{{ username }}
{% ... %}控制语句(if、for、block等){% if user %}
{# ... #}注释,不会出现在渲染结果中{# 这是注释 #}

模板示例:条件判断与循环

templates/user.html:

<!DOCTYPE html> <html> <head> <title>{{ username }} - RUNOOB</title> </head> <body> <h1>{{ username }} 的个人主页</h1> <!-- 条件判断 --> {% if posts %} <h2>最近文章:</h2> <ul> <!-- 循环遍历 --> {% for post in posts %} <li>{{ loop.index }}. {{ post.title }} ({{ post.date }})</li> {% endfor %} </ul> {% else %} <p>暂无文章</p> {% endif %} <!-- 使用过滤器 --> <p>用户名大写:{{ username|upper }}</p> </body> </html>

3. 常用过滤器

过滤器用于修改变量的输出格式,使用管道符|调用。

过滤器作用示例输出
upper转大写{{ "hello"|upper }}HELLO
lower转小写{{ "HELLO"|lower }}hello
title首字母大写{{ "hello world"|title }}Hello World
length获取长度{{ [1,2,3]|length }}3
default设置默认值{{ name|default("匿名") }}匿名(当name为空时)
safe标记为安全HTML(不转义){{ "<b>粗体</b>"|safe }}渲染为粗体文字
join连接列表{{ ["a","b"]|join(",") }}a,b

⚠️安全警告safe过滤器会关闭自动转义,只在绝对信任数据来源时使用。对于用户输入的内容,永远不要使用safe

4. 自动转义——XSS防护

Jinja2默认会对所有变量输出进行HTML转义,这是Web安全的一道关键防线。

例如,如果用户提交的用户名是<script>alert("xss")</script>,模板渲染时会自动转换为安全文本:

<!-- 模板中直接使用变量 --> <p>{{ username }}</p> <!-- 渲染结果(HTML特殊字符已被转义) --> &lt;p&gt;&amp;lt;script&amp;gt;alert(&amp;quot;xss&amp;quot;)&amp;lt;/script&amp;gt;&lt;/p&gt;

转义适用于.html.htm.xml.xhtml.svg结尾的模板文件。

5. 模板继承——消除重复代码

模板继承是Jinja2最强大的功能之一,它让你可以定义一个「基础布局」,然后通过子模板填充内容。这避免了在每个页面中重复编写头部、导航、页脚等公共部分。

基础模板(父模板)

templates/base.html:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{% block title %}RUNOOB Flask 教程{% endblock %}</title> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> </head> <body> <header> <h1>RUNOOB Flask 教程</h1> <nav> <a href="/">首页</a> | <a href="/about">关于</a> </nav> </header> <main> {% block content %}{% endblock %} </main> <footer> <p>&copy; 2026 RUNOOB.com</p> </footer> </body> </html>

子模板(继承父模板)

templates/index.html:

{% extends "base.html" %} {% block title %}RUNOOB 教程 - 首页{% endblock %} {% block content %} <h2>欢迎来到 RUNOOB</h2> <p>{{ greeting }}</p> {% if user %} <p>当前用户:{{ user }}</p> {% else %} <p><a href="/login">请先登录</a></p> {% endif %} {% endblock %}
标签作用
{% extends "base.html" %}声明当前模板继承自base.html(必须放在第一行)
{% block name %}...{% endblock %}定义一个可被子模板覆盖的区域
{{ super() }}在子模板block中调用父模板同名block的内容

使用模板继承后,你只需要修改base.html一处,所有页面的公共部分(如导航、页脚)都会自动更新。

6. 模板中的内置对象

以下Flask对象在模板中可以直接使用,无需通过render_template()传递

对象说明模板中使用示例
request当前请求对象{{ request.path }}
session当前会话数据{{ session.get("username") }}
g请求级全局变量{{ g.user }}
config应用配置{{ config["APP_NAME"] }}
url_for()URL生成函数{{ url_for("index") }}
get_flashed_messages()获取flash消息{% for msg in get_flashed_messages() %}

7. 包含其他模板——include

使用{% include %}可以在一个模板中嵌入另一个模板,适用于导航栏、侧边栏等可复用组件。

templates/_navbar.html(下划线开头表示这是一个局部模板):

<nav style="background:#f0f0f0;padding:10px;"> <a href="/">首页</a> | <a href="/posts">文章</a> | <a href="/about">关于</a> </nav>

在任意模板中引入:

<!DOCTYPE html> <html> <head><title>页面</title></head> <body> {% include "_navbar.html" %} <h1>页面内容</h1> <p>这是页面主体内容。</p> </body> </html>

最佳实践:模板继承(extends)用于页面级的布局复用,include用于组件级的代码复用。

8. 完整示例:博客首页

app.py:

from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): articles = [ {"id": 1, "title": "Flask 入门指南", "author": "runoob", "views": 1024}, {"id": 2, "title": "Jinja2 模板详解", "author": "admin", "views": 512}, {"id": 3, "title": "RESTful API 设计", "author": "runoob", "views": 256}, ] return render_template("blog.html", articles=articles)

templates/blog.html:

{% extends "base.html" %} {% block title %}RUNOOB 博客{% endblock %} {% block content %} <h2>最新文章</h2> {% if articles %} {% for article in articles %} <div class="article" {% if article.views > 1000 %}style="background:#fff3cd;"{% endif %}> <h3>{{ article.title }}</h3> <p>作者:{{ article.author }} | 浏览:{{ article.views }}</p> {% if not loop.last %} <hr> {% endif %} </div> {% endfor %} {% else %} <p>暂时没有文章,请稍后再来。</p> {% endif %} {% endblock %}

9. Jinja2循环特殊变量

{% for %}循环中,Jinja2提供了以下内置变量:

变量说明
loop.index当前循环索引,从1开始
loop.index0当前循环索引,从0开始
loop.first是否为第一次循环
loop.last是否为最后一次循环
loop.length序列总长度

10. 模板语法速查表

用途语法示例
变量输出{{ variable }}{{ username }}
变量输出(带默认值){{ variable|default("默认") }}{{ name|default("匿名") }}
条件判断{% if condition %}...{% endif %}{% if user %}
条件判断(多分支){% if %}...{% elif %}...{% else %}...{% endif %}同上
循环遍历{% for item in list %}...{% endfor %}{% for post in posts %}
循环(空时){% for %}...{% else %}...{% endfor %}列表为空时显示备用内容
模板继承{% extends "base.html" %}必须放在第一行
定义块{% block name %}...{% endblock %}{% block content %}
包含模板{% include "partial.html" %}组件复用
注释{# 注释内容 #}不会出现在渲染结果中

小结

本章全面讲解了Flask的模板渲染系统。render_template()是渲染模板的核心函数;Jinja2的{{ }}用于变量输出(自动转义防XSS),{% %}用于控制语句(if判断、for循环);过滤器通过|修改变量输出格式;模板继承通过{% extends %}{% block %}消除重复代码,实现页面级布局复用;{% include %}实现组件级复用;模板中可直接使用requestsessionurl_for()等内置对象。模板引擎让业务逻辑与页面展示分离,是构建动态Web应用的关键工具。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询