一、什么是Jinja2模板引擎?¶
在Web开发中,我们常常需要将动态数据(比如从数据库获取的用户信息、文章列表)和静态页面(HTML)结合起来,生成最终的网页。模板引擎就是用来解决这个问题的工具——它允许我们在HTML中嵌入代码逻辑,动态生成内容。
Flask框架默认使用Jinja2作为模板引擎,它是一个功能强大且语法简洁的Python模板引擎。Jinja2支持变量、条件判断、循环、模板继承等特性,能让我们更高效地编写可复用、易维护的模板代码。
二、Jinja2基础语法¶
1. 变量与表达式¶
模板中最基础的操作是显示变量。使用{{ 变量名 }}语法嵌入变量,变量由视图函数(Python代码)传递给模板。
示例:
假设在视图函数中定义了变量username = "小明",在模板中这样写:
<p>欢迎,{{ username }}!</p>
渲染后会输出:欢迎,小明!
变量可以是字符串、数字、列表、字典等,也可以访问其属性或索引:
<!-- 字典 -->
<p>{{ user.age }}</p> <!-- user是字典,输出user的age值 -->
<!-- 列表 -->
<p>{{ users[0] }}</p> <!-- users是列表,输出第一个元素 -->
2. 控制结构:条件与循环¶
Jinja2支持条件判断和循环,让模板能根据不同情况动态渲染内容。
条件判断(if-else):
{% if is_login %}
<p>欢迎回来!</p>
{% else %}
<p>请先登录</p>
{% endif %}
循环(for):
遍历列表或字典时使用{% for %},并通过loop变量获取循环状态(如是否为第一个元素、总长度等):
<ul>
{% for item in todo_list %}
<li>
{{ loop.index }}. {{ item }}
{% if loop.last %} <!-- 判断是否为最后一个元素 -->
<small>(这是最后一项)</small>
{% endif %}
</li>
{% endfor %}
</ul>
如果循环的列表为空,可通过{% else %}显示默认内容:
{% for item in todo_list %}
<li>{{ item }}</li>
{% else %}
<p>列表为空</p>
{% endfor %}
3. 模板继承与包含¶
为了避免重复代码,Jinja2提供模板继承和模板包含功能。
模板继承(Extend):
- 定义一个父模板(如base.html),包含通用结构(头部、底部、导航栏)。
- 子模板通过{% extends "base.html" %}继承父模板,并覆盖需要修改的部分。
父模板(base.html):
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
<header>
{% block header %}<h1>网站头部</h1>{% endblock %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}<p>网站底部</p>{% endblock %}
</footer>
</body>
</html>
子模板(index.html):
{% extends "base.html" %} <!-- 继承父模板 -->
{% block title %}首页{% endblock %} <!-- 覆盖title块 -->
{% block content %} <!-- 覆盖content块 -->
<p>这是首页内容</p>
<ul>
<li>项目1</li>
<li>项目2</li>
</ul>
{% endblock %}
模板包含(Include):
将其他模板片段(如头部、底部)直接插入当前模板,用于复用通用代码:
<!-- 在子模板中包含header.html -->
{% include "header.html" %}
4. 过滤器:处理变量¶
过滤器(Filter)用于对变量进行加工(如大小写转换、截断文本等),使用|符号连接。
常用过滤器:
- upper/lower:转大写/小写
{{ name|upper }} → 输出NAME
- capitalize:首字母大写
{{ name|capitalize }} → 输出Name
- truncate(n):截断文本(保留前n个字符)
{{ long_text|truncate(20) }} → 截断长文本为前20字符
- safe:禁用HTML转义(谨慎使用,防止XSS攻击)
{{ raw_html|safe }} → 直接渲染HTML代码
示例:
<p>{{ "hello"|upper }}</p> <!-- 输出HELLO -->
<p>{{ "123"|int + 456 }}</p> <!-- 转换为整数后相加 -->
<p>{{ "Flask is great!"|truncate(10) }}</p> <!-- 截断为前10字符:Flask is gr -->
三、Flask与Jinja2的结合使用¶
1. 模板文件结构¶
Flask默认从项目根目录下的templates文件夹加载模板文件。项目结构示例:
myapp/
├── app.py
└── templates/
├── base.html
├── index.html
└── user.html
2. 渲染模板的核心函数¶
视图函数通过render_template函数渲染模板,并传递变量:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
# 准备数据
users = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30}
]
return render_template('index.html', users=users) # 传递users到模板
if __name__ == '__main__':
app.run(debug=True)
3. 完整示例:用户列表页面¶
模板文件(templates/user_list.html):
{% extends "base.html" %} <!-- 继承base.html -->
{% block content %}
<h1>用户列表</h1>
<ul>
{% for user in users %} <!-- 遍历users列表 -->
<li>
{{ loop.index }}. {{ user.name }} ({{ user.age }}岁)
{% if user.age > 28 %}
<span style="color:red;">(已成年)</span>
{% endif %}
</li>
{% else %}
<p>暂无用户</p>
{% endfor %}
</ul>
{% endblock %}
视图函数(app.py):
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/users')
def user_list():
# 模拟数据库查询结果
user_data = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
{"name": "Charlie", "age": 22}
]
return render_template('user_list.html', users=user_data) # 传递数据到模板
if __name__ == '__main__':
app.run(debug=True)
四、总结与学习建议¶
Jinja2是Flask的核心组件,掌握其语法能极大提升Web开发效率。重点需掌握:
1. 变量与表达式:{{ variable }}
2. 控制结构:if-else、for循环
3. 模板复用:继承(extends)和包含(include)
4. 过滤器:|符号处理变量
建议通过以下方式实践:
- 搭建一个简单的个人博客,使用模板继承实现导航栏复用
- 练习循环展示文章列表,结合过滤器截断长文本
- 尝试使用safe过滤器渲染富文本内容
通过多写多练,你会逐渐熟悉Jinja2的灵活语法,让你的Flask应用更优雅、更高效!