Skip to content

Flask - 模板

虽然你可以直接从 Flask 视图函数返回 HTML 字符串,但这很快就会变得难以管理,并且将表示逻辑与应用逻辑混杂在一起。Flask 集成了强大的 Jinja2 模板引擎来解决这个问题。

相比于在 Python 中构建 HTML 字符串:

Section titled “相比于在 Python 中构建 HTML 字符串:”
# Less maintainable approach
# 可维护性较差的方法
@app.route('/old')
def old_hello():
user = 'Alice'
# Embedding HTML directly in Python code
# 直接在 Python 代码中嵌入 HTML
return f'<html><body><h1>Hello {user}!</h1></body></html>'
  1. 创建带有特殊占位符的 HTML 文件(模板),用于动态内容。

  2. 在视图函数中使用 Flask 的 render_template() 函数来渲染这些模板,并传递任何必要的数据。

要渲染模板,你需要从 Flask 导入 render_template,并在你的视图函数中调用它,提供模板文件名以及你想以关键字参数形式传递给模板的任何变量。

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/hello/<name>')
def hello(name):
# Renders 'templates/user_greeting.html'
# 渲染 'templates/user_greeting.html'
# Passes the 'name' variable from the URL to the template
# 将 URL 中的 'name' 变量传递给模板
# under the variable name 'username'.
# 变量名为 'username'。
return render_template('user_greeting.html', username=name)
if __name__ == '__main__':
app.run(debug=True)

默认情况下,Flask 在与主应用脚本或包相同的目录中查找名为 templates 的子文件夹中的模板。

/your_project
app.py
/templates
user_greeting.html
layout.html
# ... other templates
# ... 其他模板

Jinja2 模板主要是包含特殊分隔符的 HTML 文件,用于嵌入逻辑和变量:

  • {{ ... }} 用于表达式: 用于将变量的值或表达式的结果打印到模板输出中。为了安全起见,Jinja2 会自动处理 HTML 转义。
  • {% ... %} 用于语句: 用于控制结构,如循环 (for)、条件 (if/elif/else)、模板继承 (extends、block) 和宏。
  • {# ... #} 用于注释: 用于模板引擎忽略的注释,不会出现在最终的 HTML 输出中。

模板示例(templates/user_greeting.html):

Section titled “模板示例(templates/user_greeting.html):”
<!DOCTYPE html>
<html>
<head>
<title>Greeting</title>
</head>
<body>
{# This is a comment, it won't be rendered #}
{# 这是一个注释,它不会被渲染 #}
{# Print the 'username' variable passed from Flask #}
{# 打印从 Flask 传递过来的 'username' 变量 #}
<h1>Hello, {{ username }}!</h1>
<p>Welcome to our application.</p>
<p>欢迎来到我们的应用。</p>
</body>
</html>

运行上面的示例,并访问 /hello/Bob,会渲染出这个 HTML,并将 {{ username }} 替换为 Bob。

你可以在 {% ... %} 块中使用类似 Python 的控制结构。

@app.route('/grade/<int:score>')
def show_grade(score):
return render_template('grade_result.html', marks=score)

模板(templates/grade_result.html):

Section titled “模板(templates/grade_result.html):”
<!DOCTYPE html>
<html>
<body>
<h1>Exam Result</h1>
<h1>考试结果</h1>
{% if marks >= 90 %}
<p>Grade: A</p>
<p>等级:A</p>
{% elif marks >= 75 %}
<p>Grade: B</p>
<p>等级:B</p>
{% elif marks >= 60 %}
<p>Grade: C</p>
<p>等级:C</p>
{% else %}
<p>Grade: F - Please see instructor.</p>
<p>等级:F - 请联系教师。</p>
{% endif %}
</body>
</html>
@app.route('/items')
def show_items():
item_list = ['Apple', 'Banana', 'Cherry']
return render_template('item_list.html', items=item_list)
<!DOCTYPE html>
<html>
<body>
<h1>Available Items</h1>
<h1>可用物品:</h1>
{% if items %}
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% else %}
<p>No items available.</p>
<p>暂无可用物品。</p>
{% endif %}
</body>
</html>

Jinja2 最强大的功能是模板继承。它允许你定义一个基础布局模板(例如,layout.html),包含通用元素(页头、页脚、导航),并定义子模板可以覆盖的特定块。

基础模板(templates/layout.html):

Section titled “基础模板(templates/layout.html):”
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Application{% endblock %}</title>
<title>{% block title %}我的应用{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<header>
<h1>My Website</h1>
<h1>我的网站</h1>
</header>
<main>
{% block content %}
{# Child templates will put their content here #}
{# 子模板会将它们的内容放在这里 #}
{% endblock %}
</main>
<footer>
<p>&copy; 2023 Me</p>
<p>&copy; 2023 我</p>
</footer>
</body>
</html>

子模板(更新后的 templates/user_greeting.html):

Section titled “子模板(更新后的 templates/user_greeting.html):”
{% extends 'layout.html' %}
{% block title %}Greeting for {{ username }}{% endblock %}
{% block title %}问候 {{ username }}{% endblock %}
{% block content %}
<h2>Hello, {{ username }}!</h2>
<h2>你好,{{ username }}!</h2>
<p>Welcome to our application.</p>
<p>欢迎来到我们的应用。</p>
{% endblock %}

当渲染 user_greeting.html 时,Jinja2 将:

  1. 加载 layout.html。
  2. 将 layout.html 中的 {% block title %} 替换为 user_greeting.html 中 {% block title %} 的内容。
  3. 将 layout.html 中的 {% block content %} 替换为 user_greeting.html 中 {% block content %} 的内容。

这促进了代码重用,并使得在整个应用中保持一致的外观和感觉变得容易得多。