如何在Flask应用程序中使用模板

作者选择了自由与开源基金会作为写作捐赠计划的一部分接受捐赠。

引言

Flask 是一个轻量级的Python网络框架,为使用Python语言创建网络应用提供了有用的工具和功能。

在开发网络应用时,将业务逻辑展示逻辑分开至关重要。业务逻辑负责处理用户请求并与数据库通信以构建适当的响应。展示逻辑则是如何将数据呈现给用户,通常使用HTML文件构建响应网页的基本结构,并利用CSS样式来设计HTML组件。例如,在社交媒体应用中,当用户未登录时,可能只显示用户名和密码字段;若用户已登录,则显示登出按钮。这就是展示逻辑的体现。如果用户输入了用户名和密码,你可以利用Flask执行业务逻辑:从请求中提取数据(用户名和密码),验证凭据正确则登录用户,否则返回错误信息。错误信息的显示方式则由展示逻辑处理。

在 Flask 中,你可以使用 Jinja 模板语言来渲染 HTML 模板。模板是一个文件,可以包含固定内容和动态内容。当用户从你的应用程序请求某些内容(如首页或登录页)时,Jinja 允许你响应一个 HTML 模板,在其中可以使用标准 HTML 中不可用的许多功能,如变量、if 语句、for 循环、过滤器和模板继承。这些功能使你能够高效编写易于维护的 HTML 页面。Jinja 还会自动转义 HTML,以防止 跨站脚本(XSS) 攻击。

在本教程中,你将构建一个渲染多个 HTML 文件的小型 Web 应用程序。你将使用变量将数据从服务器传递到模板。模板继承将帮助你避免重复。你将在模板中使用条件和循环等逻辑,使用过滤器修改文本,并使用 Bootstrap 工具包 来美化你的应用程序。

前提条件

步骤1 — 渲染模板并使用变量

确保你已激活环境并安装了Flask,然后就可以开始构建你的应用了。第一步是在首页显示一条欢迎访客的消息。你将使用Flask的render_template()辅助函数来提供一个HTML模板作为响应。你还将了解如何从应用端向模板传递变量。

首先,在你的flask_app目录中,打开一个名为app.py的文件进行编辑。使用nano或你喜欢的文本编辑器:

  1. nano app.py

app.py文件中添加以下代码:

flask_app/app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html')

保存并关闭文件。

在这段代码中,你从flask包导入了Flask类和render_template()函数。你使用Flask类创建了一个名为app的Flask应用实例。然后,你通过app.route()装饰器定义了一个视图函数(即返回HTTP响应的Python函数),名为hello()。该视图函数使用render_template()函数来渲染一个名为index.html的模板文件。

接下来,你需要在flask_app目录内的templates目录中创建一个名为index.html的模板文件。Flask会在名为templates模板目录中查找模板,因此这个名称很重要。确保你位于flask_app目录中,并运行以下命令来创建templates目录:

  1. mkdir templates

接下来,在templates目录中打开一个名为index.html的文件进行编辑。这里的index.html并不是一个标准要求的名称;如果你愿意,可以将其命名为home.htmlhomepage.html或其他任何名称:

  1. nano templates/index.html

index.html文件中添加以下HTML代码:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
</body>
</html>

在这里,你设置了一个标题,添加了一条Hello World!消息作为H1标题,并创建了一条Welcome to FlaskApp!消息作为H2标题。

保存并关闭文件。

在激活了虚拟环境的flask_app目录中,使用FLASK_APP环境变量告诉Flask应用程序的位置(在你的例子中是app.py),并将FLASK_ENV环境变量设置为development,以开发模式运行应用程序并启用调试器。使用以下命令来完成这一操作(在Windows上,使用set代替export):

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

然后,使用flask run命令运行应用程序:

  1. flask run

在开发服务器运行的情况下,使用浏览器访问以下URL:

http://127.0.0.1:5000/

页面标题设置为 `FlaskApp`,两个标题则渲染为 HTML。

在网页应用中,你经常需要将应用的 Python 文件中的数据传递到 HTML 模板。为了演示如何在此应用中实现这一点,你将传递一个包含当前 UTC 日期和时间的变量到索引模板,并在模板中显示该变量的值。

保持服务器运行,并在新终端中打开 `app.py` 文件进行编辑:

  1. nano app.py

从 Python 标准库中导入 `datetime` 模块,并修改 `index()` 函数,使文件内容如下:

flask_app/app.py
import datetime
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html', utc_dt=datetime.datetime.utcnow())

保存并关闭文件。

这里你导入了 `datetime` 模块,并向 `index.html` 模板传递了一个名为 `utc_dt` 的变量,其值为 `datetime.datetime.utcnow()`,即当前的 UTC 日期和时间。

接下来,要在索引页上显示该变量的值,请打开 `index.html` 文件进行编辑:

  1. nano templates/index.html

将文件修改如下:

flask_app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
</body>
</html>

保存并关闭文件。

你添加了一个 H3 标题,并使用特殊的 `{{ ... }}` 分隔符来打印 `utc_dt` 变量的值。

打开浏览器,访问索引页面:

http://127.0.0.1:5000/

你将看到类似下图的页面:

你现在已经创建了一个带有HTML模板的Flask应用程序索引页面,渲染了一个模板,并传递和显示了一个变量值。接下来,你将通过使用模板继承来避免代码重复。

步骤2 — 使用模板继承

在这一步中,你将创建一个包含可与其他模板共享内容的基模板。你将编辑你的索引模板以继承自基模板。然后,你将创建一个新页面,作为你的应用程序的“关于”页面,用户可以在那里找到更多关于你的应用程序的信息。

一个基模板包含通常在所有其他模板之间共享的HTML组件,例如应用程序的标题、导航栏和页脚。

首先,在你的模板目录中打开一个名为base.html的新文件进行编辑:

  1. nano templates/base.html

在你的base.html文件中编写以下代码:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="#">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

保存并关闭文件。

这个文件中的大部分代码是标准的HTML,一个标题,一些用于导航链接的样式,一个带有两个链接的导航栏,一个用于索引页面,另一个用于尚未创建的“关于”页面,以及一个用于页面内容的<div>。(这些链接目前还不起作用;下一步将展示如何链接页面)。

然而,以下高亮部分是特定于Jinja模板引擎的:

  • {% block title %} {% endblock %}: 一个,用作标题的占位符。稍后,您将在其他模板中使用它,为应用程序中的每个页面提供自定义标题,而无需每次都重写整个<head>部分。

  • {% block content %} {% endblock %}: 另一个块,将根据子模板(继承自base.html的模板)的内容进行替换,该子模板将覆盖它。

现在您有了一个基础模板,可以通过继承来利用它。打开index.html文件:

  1. nano templates/index.html

然后将其内容替换为以下内容:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Index {% endblock %}</h1>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
{% endblock %}

在这里,您使用 `{% extends %}` 标签来继承 `base.html` 模板。然后通过替换基础模板中的 `content` 块,扩展它,使其包含前述代码块中的 `content` 块内容。

这个内容块包含一个 `<h1>` 标签,其中文本为 `Index`,它位于一个标题块内,该标题块替换了 `base.html` 模板中原有的 `title` 块,使其文本变为 `Index`,从而完整标题变为 `Index - FlaskApp`。这样,您可以避免重复相同的文本,因为它既作为页面标题,又作为出现在继承自基础模板的导航栏下方的标题。

接着,您还有几个标题:一个带有文本 `Hello World!` 的 `<h1>` 标题,一个 `<h2>` 标题,以及一个包含 `utc_dt` 变量值的 `<h3>` 标题。

模板继承使您能够重用在其他模板(此处为 `base.html`)中的HTML代码,而无需每次需要时都重复编写。

保存并关闭文件,然后在浏览器中刷新索引页面。页面将显示如下:

接下来,您将创建关于页面。打开 `app.py` 文件以添加新路由:

  1. nano app.py

在文件末尾添加以下路由:

flask_app/app.py

# ...
@app.route('/about/')
def about():
    return render_template('about.html')

在这里,您使用app.route()装饰器来创建一个名为about()的视图函数。在其中,您返回调用render_template()函数的结果,并以about.html模板文件名作为参数。

保存并关闭文件。

打开一个名为about.html的模板文件进行编辑:

  1. nano templates/about.html

向文件中添加以下代码:

flask_app/templates/about.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} About {% endblock %}</h1>
    <h3>FlaskApp is a Flask web application written in Python.</h3>
{% endblock %}

此处,您通过extends标签继承自基础模板,将基础模板的content块替换为一个<h1>标签,该标签同时也作为页面的标题,并添加一个包含应用程序相关信息的<h3>标签。

保存并关闭文件。

在开发服务器运行的情况下,使用浏览器访问以下URL:

http://127.0.0.1:5000/about

您将看到一个类似如下的页面:

注意导航栏和部分标题是如何从基础模板继承而来的。

现在,您已经创建了一个基础模板,并在索引页和关于页中使用它以避免代码重复。此时,导航栏中的链接还未实现任何功能。在下一步中,您将学习如何通过修复导航栏链接来在模板中链接不同的路由。

步骤3 — 页面间链接

在这一步中,你将学习如何使用url_for()辅助函数在你的模板中进行页面间的链接。你将在基础模板中的导航栏添加两个链接,一个指向首页,另一个指向关于页面。

首先打开你的基础模板进行编辑:

  1. nano templates/base.html

编辑文件使其如下所示:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

这里,你使用了特殊的url_for()函数,它会返回你提供的视图函数的URL。第一个链接指向hello()视图函数的路由(即首页)。第二个链接指向about()视图函数的路由。注意,你传递的是视图函数的名称,而不是路由(如//about)。

使用url_for()函数来构建URL有助于更好地管理URL。如果你硬编码URL,修改路由时链接将会失效。而使用url_for(),你可以修改路由并确保链接仍能正常工作。url_for()函数还会处理转义特殊字符等其他事项。

保存并关闭文件。

现在前往首页,尝试导航栏中的链接。你会发现它们如预期般工作。

你已经学会了如何在模板中使用 `url_for()` 函数链接到其他路由。接下来,你将添加一些条件语句,根据你设定的条件控制模板中显示的内容,并在模板中使用 `for` 循环来显示列表项。

步骤 4 — 使用条件语句和循环

在这一步中,你将在模板中使用 `if` 语句来根据特定条件控制显示内容。你还将使用 `for` 循环遍历 Python 列表,并在列表中显示每个项目。你将添加一个新页面,以列表形式显示评论。索引号为偶数的评论将具有蓝色背景,而索引号为奇数的评论将显示为灰色背景。

首先,你将为评论页面创建一个路由。打开你的 `app.py` 文件进行编辑:

  1. nano app.py

在文件末尾添加以下路由:

flask_app/app.py

# ...

@app.route('/comments/')
def comments():
    comments = ['This is the first comment.',
                'This is the second comment.',
                'This is the third comment.',
                'This is the fourth comment.'
                ]

    return render_template('comments.html', comments=comments)

在上面的路由中,你有一个名为 `comments` 的 Python 列表,其中包含四个项目。(在实际场景中,这些评论通常来自数据库,而不是像你在这里硬编码的那样。)你在最后一行返回一个名为 `comments.html` 的模板文件,并将包含列表的变量 `comments` 传递给模板文件。

保存并关闭文件。

接下来,在 `templates` 目录中打开一个新的 `comments.html` 文件进行编辑:

  1. nano templates/comments.html

将以下代码添加到文件中:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
        <div style="padding: 10px; background-color: #EEE; margin: 20px">
            <p style="font-size: 24px">{{ comment }}</p>
        </div>
        {% endfor %}
    </div>
{% endblock %}

在这里,你扩展了 `base.html` 模板并替换了 `content` 块的内容。首先,你使用一个 `

` 标题,它同时也作为页面的标题。

你在 `{% for comment in comments %}` 这一行使用了一个 Jinja 的 `for` 循环,来遍历 `comments` 列表中的每一个评论(这些评论会被存储在 `comment` 变量中)。你通过 `

{{ comment }}

` 标签来显示评论,这与在 Jinja 中正常显示变量的方式相同。你使用 `{% endfor %}` 关键字来标识 `for` 循环的结束。这与 Python 的 `for` 循环构造不同,因为在 Jinja 模板中没有特殊的缩进要求。

保存并关闭文件。

在开发服务器运行的情况下,打开浏览器并访问评论页面:

http://127.0.0.1:5000/comments

你将看到类似以下的页面:

现在,你将在模板中使用 `if` 条件语句,通过显示奇数索引号的评论带有灰色背景,偶数索引号的评论带有蓝色背景。

打开你的 `comments.html` 模板文件进行编辑:

  1. nano templates/comments.html

编辑使其如下所示:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index % 2 == 0 %}
                {% set bg_color = '#e6f9ff' %}
            {% else %}
                {% set bg_color = '#eee' %}
            {% endif %}

            <div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

通过这次编辑,你在代码行 `{% if loop.index % 2 == 0 %}` 中添加了一个 `if` 语句。这里的 `loop` 变量是 Jinja 的一个特殊变量,它提供了关于当前循环的信息。在这里,你使用 `loop.index` 来获取当前项的索引,该索引从 `1` 开始,不同于 Python 列表中的 `0` 开始。

这个 `if` 语句通过使用 `%` 运算符来检查索引是否为偶数。它检查索引数除以 `2` 的余数;如果余数为 `0`,则意味着索引数是偶数,否则索引数是奇数。你使用 `{% set %}` 标签声明了一个名为 `bg_color` 的变量。如果索引数是偶数,你将其设置为一种偏蓝色的颜色,否则,如果索引数是奇数,你将 `bg_color` 变量设置为灰色。然后,你使用 `bg_color` 变量为包含评论的 `<div>` 标签设置背景颜色。在评论文本上方,你使用 `loop.index` 在 `<p>` 标签中显示当前索引号。

保存并关闭文件。

打开浏览器并访问评论页面:

http://127.0.0.1:5000/comments

你将看到新的评论页面:

这是展示如何使用 `if` 语句的一个示例。但通过使用 Jinja 的特殊辅助函数 `loop.cycle()`,你也可以实现同样的效果。为了演示这一点,打开 `comments.html` 文件:

  1. nano templates/comments.html
flask_app/templates/comments.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            <div style="padding: 10px;
                        background-color: {{ loop.cycle('#EEE', '#e6f9ff') }};
                        margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

在这里,你移除了 if/else 语句,并使用了 loop.cycle('#EEE', '#e6f9ff') 助手来在两种颜色之间循环。background-color 的值将会是 #EEE 一次,然后是 #e6f9ff 另一次。

保存并关闭文件。

在浏览器中打开评论页面,刷新它,你会发现这与使用 if 语句的效果相同。

你可以使用 if 语句实现多种功能,包括控制页面上显示的内容。例如,要显示除第二条评论之外的所有评论,你可以使用条件为 loop.index != 2if 语句来过滤掉第二条评论。

打开评论模板:

  1. nano templates/comments.html

并编辑成如下形式:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

在这里,你使用 {% if loop.index != 2 %} 来显示索引不是 2 的评论,这意味着所有评论除了第二条。你还使用了一个硬编码的背景颜色值,而不是 loop.cycle() 助手,以简化操作,其余部分保持不变。你使用 {% endif %} 结束 if 语句。

保存并关闭文件。

刷新评论页面,你会发现第二条评论没有显示。

现在你需要在导航栏中添加一个链接,将用户带到评论页面。打开基础模板进行编辑:

  1. nano templates/base.html

编辑 `

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('comments') }}">Comments</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

在这里,你使用 `url_for()` 助手链接到 `comments()` 视图函数。

保存并关闭文件。

导航栏现在会有一个新的链接,指向评论页面。

你在模板中使用了 `if` 语句来根据特定条件控制显示内容。你使用了 `for` 循环遍历 Python 列表并显示每个项目,并且你了解了 Jinja 中的特殊 `loop` 变量。接下来,你将使用 Jinja 过滤器来控制变量数据的显示方式。

步骤 5 — 使用过滤器

在这一步中,你将学习如何在模板中使用 Jinja 过滤器。你将使用 `upper` 过滤器将上一步添加的评论转换为大写,使用 `join` 过滤器将一系列字符串连接成一个字符串,并学习如何使用 `safe` 过滤器在不转义的情况下渲染受信任的 HTML 代码。

首先,你将把评论页面中的评论转换为大写。打开 `comments.html` 模板进行编辑:

  1. nano templates/comments.html

编辑它,使其如下所示:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

在这里,您通过管道符号(|)添加了upper 过滤器。这将修改comment变量的值,使其变为大写。

保存并关闭文件。

在开发服务器运行的情况下,用浏览器打开评论页面:

http://127.0.0.1:5000/comments

应用过滤器后,您可以看到评论全部变成了大写。

过滤器还可以接受括号中的参数。为了演示这一点,您将使用join过滤器将comments列表中的所有评论连接起来。

打开评论模板:

  1. nano templates/comments.html

编辑使其如下所示:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            <p>{{ comments | join(" | ") }}</p>
        </div>
    </div>
{% endblock %}

在这里,您添加了一个<hr>标签和一个<div>标签,其中使用join()过滤器将comments列表中的所有评论连接起来。

保存并关闭文件。

刷新评论页面,您将看到类似以下的页面:

如您所见,comments列表显示为评论之间用管道符号分隔,这是您传递给join()过滤器的参数。

另一个重要的过滤器是 `safe` 过滤器,它允许你在浏览器中渲染受信任的HTML。为了说明这一点,你将在评论模板中使用 `{{ }}` Jinja 分隔符添加一些包含HTML标签的文本。在实际应用中,这些内容通常来自服务器变量。然后,将 `join()` 参数改为 `<hr>` 标签,而不是管道符号。

打开评论模板:

  1. nano templates/comments.html

编辑使其如下所示:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" }}
            <p>{{ comments | join(" <hr> ") }}</p>
        </div>
    </div>
{% endblock %}

在这里,你添加了值 `"<h1>COMMENTS</h1>"` 并将连接参数改为 `<hr>` 标签。

保存并关闭文件。

刷新评论页面,你会看到类似以下的页面:

可以看到,HTML标签并未被渲染。这是Jinja的安全特性,因为某些HTML标签可能有害,可能导致 跨站脚本(XSS) 攻击。你应仅允许受信任的HTML在浏览器中渲染。

为了渲染上述HTML标签,打开评论模板文件:

  1. nano templates/comments.html

通过添加 `safe` 过滤器进行编辑:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" | safe }}
            <p>{{ comments | join(" <hr> ") | safe }}</p>
        </div>
    </div>
{% endblock %}

你可以看到,也可以像在行 `<p>{{ comments | join(" <hr> ") | safe }}</p>` 中那样链式使用过滤器。每个过滤器应用于前一个过滤的结果。

保存并关闭文件。

刷新评论页面,你会看到HTML标签现在按预期渲染了:

警告:在处理来自未知数据源的HTML时使用safe过滤器可能会使您的应用程序面临XSS攻击的风险。除非渲染的HTML来自可信源,否则请勿使用它。

更多信息,请查看Jinja内置过滤器列表

您现在已了解如何在Jinja模板中使用过滤器来修改变量值。接下来,您将集成Bootstrap工具包来美化您的应用程序。

步骤6 — 集成Bootstrap

在这一步中,您将学习如何使用Bootstrap工具包来美化您的应用程序。您将在基础模板中添加一个Bootstrap导航栏,该导航栏将出现在所有继承自基础模板的页面中。

Bootstrap工具包有助于您美化应用程序,使其更具视觉吸引力。它还能帮助您在Web应用程序中加入响应式网页,以便在移动浏览器上良好运行,而无需自行编写HTML、CSS和JavaScript代码来实现这些目标。

要使用Bootstrap,您需要将其添加到基础模板中,以便在所有其他模板中使用。

打开你的 `base.html` 模板,进行编辑:

  1. nano templates/base.html

将其编辑成如下内容:

flask_app/templates/base.html
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">

    <title>{% block title %} {% endblock %} - FlaskApp</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="{{ url_for('hello') }}">FlaskApp</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('comments') }}">Comments</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('about') }}">About</a>
            </li>
        </ul>
        </div>
    </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>

  </body>
</html>

上述代码大部分是使用 Bootstrap 所需的样板代码。你有一些元标签,在 `<head>` 部分链接到 Bootstrap 的 CSS 文件,底部则链接到可选的 JavaScript。代码中高亮的部分包含了在前几步中解释的 Jinja 代码。注意你如何使用特定的标签和 CSS 类来告诉 Bootstrap 如何显示每个元素。

在上面的 `<nav>` 标签中,你有一个带有 `navbar-brand` 类的 `<a>` 标签,它决定了导航栏中的品牌链接。在 `<ul class="navbar-nav">` 标签内部,你有一个 `<li>` 标签内的 `<a>` 标签,包含了常规的导航栏项目。

要了解更多关于这些标签和 CSS 类的信息,请参阅 Bootstrap 组件

保存并关闭文件。

在开发服务器运行的情况下,用浏览器打开索引页面:

http://127.0.0.1:5000/

你会看到类似以下的页面:

现在你可以在所有模板中使用 Bootstrap 组件来为 Flask 应用程序中的项目进行样式设计。

结论

你现在了解了如何在 Flask 网络应用中使用 HTML 模板。你通过变量将数据从服务器传递到模板,利用模板继承来避免重复,引入了诸如 `if` 条件语句和 `for` 循环等元素,并实现了不同页面间的链接。你还学习了如何使用过滤器来修改文本和显示受信任的 HTML,并将 Bootstrap 集成到你的应用中。

如果你想进一步了解 Flask,可以查阅Flask 主题页面

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-a-flask-application