Flask入门教程(九):模板渲染——用Jinja2构建动态页面

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 }}`
lower 转小写 `{``{ "HELLO" lower }}`
title 首字母大写 `{``{ "hello world" title }}`
length 获取长度 `{``{ [1,2,3] length }}`
default 设置默认值 `{``{ name default("匿名") }}`
safe 标记为安全HTML(不转义) `{``{ "粗体" safe }}`
join 连接列表 `{``{ ["a","b"] join(",") }}`

⚠️ 安全警告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("默认") }}`
条件判断 {% 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应用的关键工具。

相关推荐
QQ_216962909616 分钟前
【源码编号:project93375】SpringBoot汽车维修管理信息系统:客户车辆、维修预约、工单派发、配件结算全流程实战
java·spring boot·后端·汽车·springboot·需求分析
2601_9668714022 分钟前
AE影视后期特效-遮罩/调色/抠像/MG动画/3D/Vlog制作(完结)jzit
python
circuitsosk40 分钟前
大模型本体安全防护实践:提示词注入防御、输出合规过滤与敏感信息脱敏
python·安全·数据脱敏·纵深防御·提示词注入·llmsecurity
工业一体机老司机1 小时前
Python实现工业一体机Modbus-TCP通信-从协议解析到多设备轮询实战
开发语言·python·tcp/ip
2401_885885041 小时前
国际语音php接口代码示例:PHP使用cURL快速调用语音发送API
android·开发语言·前端·人工智能·python·php·语音识别
gis开发之家1 小时前
Spring Boot 4 深度解析,JdbcTemplate 实战——轻量级数据库操作方案
java·数据库·spring boot·后端
EW Frontier1 小时前
基于 Python + NumPy 的雷达信号处理仿真平台设计与实现——从 LFM 波形到 CFAR 检测的完整信号链
python·雷达信号处理·cfar\]·mti·mtd
axinawang2 小时前
Tesseract入门--把图片里印刷文字提取成文本
python
青 春 记 忆2 小时前
LeetCode 283. 移动零|Python 解法详解
python·算法·leetcode