在上一阶段,我们一起学习了基于Python地 web框架Flask,并且初步了解了这个框架有一种渲染方式叫做 模板语法,今天,我们一起再来深入地了解和学习这个叫做Jinja2地模板语法。
Flask 的模板渲染由Jinja2提供支持,Jinja2 是一个强大的 Python 模板引擎。现在假设你已经对它有了基本的了解,所以接下来让我们更深入地了解 Flask 模板渲染的高级功能和最佳实践。
1. Jinja2 模板语法回顾
在进一步介绍之前,这里先简单概述一下 Jinja2 的语法:
- 变量 :
{``{ variable }}
- 控制结构 :
{% if condition %} ... {% endif %}
,{% for item in items %} ... {% endfor %}
- 筛选器 :
{``{ variable|filter_name }}
- 评论 :
{# This is a comment #}
- 继承 :
{% extends "base.html" %}
,{% block content %} ... {% endblock %}
根据上面的模板语法,我们使用一个例程来实现Jinja2 模板语法回顾:
代码示例:
1.1 变量
在模板中,我们可以通过 {``{ variable }}
来渲染变量的值。
示例:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Jinja2 模板语法回顾</title>
</head>
<body>
<h1>欢迎,{{ name }}!</h1>
<p>你当前的年龄是:{{ age }}岁。</p>
</body>
</html>
1.2 控制结构
使用 {% %}
来执行控制结构,例如条件判断和循环。
条件判断:
{% if age >= 18 %}
<p>你是成年人。</p>
{% else %}
<p>你是未成年人。</p>
{% endif %}
循环:
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
1.3. 过滤器
过滤器用于修改输出的值,比如格式化日期、文本转换等。使用 |
来调用过滤器。
示例:
<p>{{ "2024-12-27"|date("yyyy年MM月dd日") }}</p>
<p>{{ "Hello World"|lower }}</p>
1.4. 模板继承
可以通过 {% extends %}
和 {% block %}
实现模板的继承和重用。
基本模板(base.html):
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>{% block title %}我的网站{% endblock %}</title>
</head>
<body>
<header>
<h1>{% block header %}欢迎来到我的网站{% endblock %}</h1>
</header>
<div class="content">
{% block content %}内容区域{% endblock %}
</div>
<footer>
{% block footer %}版权信息{% endblock %}
</footer>
</body>
</html>
上面的基本模版在浏览器中的显示:
子模板(home.html):
{% extends "base.html" %}
{% block title %}首页 - 我的网站{% endblock %}
{% block content %}
<h2>欢迎来到首页!</h2>
<p>这里是一些重要的内容。</p>
{% endblock %}
上面的子模版在继承了基本模板之后,在浏览器中的显示(内容区域已经被子模版的内容替换掉了):
1.5. 自定义过滤器
你可以定义自定义的过滤器来对模板中的变量进行处理。
Python 代码(app.py):
from flask import Flask
from flask import render_template
app = Flask(__name__)
# 自定义过滤器函数
def reverse_string(value):
return value[::-1]
# 注册自定义过滤器
app.jinja_env.filters['reverse'] = reverse_string
@app.route('/')
def home():
return render_template('home.html')
if __name__ == '__main__':
app.run(debug=True)
模板代码(home.html):
<p>{{ "hello"|reverse }}</p> <!-- 输出:olleh -->
上面的webServer 运行后,在浏览器总访问效果如下:
你会发现,输入内容"hello" 被我们自己定义的反相器reverse给倒序了。这个反相器就是一个过滤器,你可以定义很多不同的过滤器,比如字符串截取、大小写变换、日期格式转换、字符串替换等等。
1.6. 模板宏
宏类似于模板中的函数,可以用来复用代码块。
示例:(macros.html)
{% macro render_item(item) %}
<div class="item">
<h3>{{ item.name }}</h3>
<p>{{ item.description }}</p>
</div>
{% endmacro %}
使用宏:(home.html)
{% from "macros.html" import render_item %}
<div class="items">
{% for item in items %}
{{ render_item(item) }}
{% endfor %}
</div>
app.js 如下
python
from flask import Flask, render_template
# 创建一个 Flask 实例
app = Flask(__name__)
@app.route('/home')
def greet():
# 定义要传递给模板的数据
items = [
{"name": "Alice", "description": "description Alice"},
{"name": "Tom", "description": "description Tom"}
]
# 将数据传递给模板
return render_template('home.html', items=items)
# 运行应用
if __name__ == '__main__':
app.run(debug=True)
上述代码执行后,从浏览器访问:
你会发现,模板宏被调用了,显示了名字和介绍。这个模板宏,可以被很多具有相同数据结构的页面调用。它形成了一个类似vue的 component 组件。
1.7. 模板包含
{% include %}
用于包含其他模板的内容,通常用于包含页面的共同部分。
示例:
<div class="sidebar">
{% include "sidebar.html" %}
</div>
通过这些语法,Jinja2 提供了灵活而强大的模板引擎,能帮助我们高效地渲染动态内容,并且让页面结构更清晰、可维护。
2.模板继承(高级)
模板继承是 Jinja2 最强大的功能之一。它允许您定义一个基本模板并在子模板中扩展它,从而实现通用布局和结构的重用。
基本模板示例:
python
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Website{% endblock %}</title>
</head>
<body>
<header>
<h1>{% block header %}Welcome to My Website{% endblock %}</h1>
</header>
<div class="content">
{% block content %}Content goes here{% endblock %}
</div>
<footer>
{% block footer %}Footer content{% endblock %}
</footer>
</body>
</html>
子模板示例:
python
{% extends "base.html" %}
{% block title %}Home - My Website{% endblock %}
{% block content %}
<h2>Welcome to the home page!</h2>
<p>Here is some important content.</p>
{% endblock %}
这个案例和我们之前回顾的模板调用实际上一样的,在此不做赘述了,需要加深理解的可以重做一遍。
3.动态模板渲染
您可以将数据动态传递给模板。将数据操作逻辑与 Flask 视图中的渲染逻辑分开是一种很好的做法。
Flask 路线示例:
python
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
data = {
'name': 'John Doe',
'age': 30,
'items': ['apple', 'banana', 'cherry']
}
return render_template('home.html', data=data)
模板示例(home.html
):
python
<h1>Hello, {{ data.name }}</h1>
<p>You are {{ data.age }} years old.</p>
<ul>
{% for item in data.items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
4.模板上下文处理器
上下文处理器是在渲染模板之前运行的函数,允许您自动将公共变量传递给所有模板。
例子:
python
@app.context_processor
def inject_user():
return {'user': 'John Doe'}
这将注入user
到每个模板中,因此您可以{``{ user }}
在任何模板中使用它而无需明确传递它。这个有点类似Node.js 的中间件,在app.j中定义好之后,继续往下路由,可以全局使用。
5.使用自定义错误页面处理错误
Flask 提供了一种定义自定义错误页面的方法(例如 404 或 500 错误)。你可以为这些错误渲染自定义模板。
例子:
- 包括 :用于
{% include 'filename.html' %}
重用模板片段。 - 动态渲染
render_template_string
:有时,您可能需要从字符串而不是文件渲染模板。 - 异步渲染:对于需要异步处理的繁重操作,您可以使用 Flask 对后台作业或流式传输数据到客户端的支持。
6.高级模板技术
- 包括 :用于
{% include 'filename.html' %}
重用模板片段。 - 动态渲染
render_template_string
:有时,您可能需要从字符串而不是文件渲染模板。 - 异步渲染:对于需要异步处理的繁重操作,您可以使用 Flask 对后台作业或流式传输数据到客户端的支持。
7.测试模板
Flask 有一个内置测试客户端,你可以用它来测试你的路由和模板。使用flask.testing.TestCase
,你可以断言模板的渲染是否正确。
python
from flask import Flask, render_template
import unittest
app = Flask(__name__)
@app.route('/')
def home():
return render_template('home.html', name="Test")
class TemplateTest(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
self.client = app.test_client()
def test_home_page(self):
response = self.client.get('/')
self.assertIn(b'Hello, Test', response.data)
if __name__ == '__main__':
unittest.main()
8.Flask扩展
Flask 有许多可以简化模板的扩展,例如:
- Flask-WTF:用于将表单集成到模板中。
- Flask-Login:用于管理模板中的用户会话。
除了上面这些,其他还有 循环、嵌套等方法,都很容易实现,这里就不一一赘述了。
通过学习这些高级特性,你可以更灵活地使用 Flask 的模板系统,编写更加干净、可维护和扩展的模板。你可以尝试将这些功能组合在一起,用于实现更复杂的页面和功能。如果有任何问题或不清楚的地方,欢迎随时留言一起来讨论!