Flask Jinja2模板核心语法详解:变量、块、宏与包含
本文系统总结Flask框架中Jinja2模板的常用语法,涵盖变量表示、赋值操作、条件判断与循环结构。深入解析Block块继承机制,包括内容覆盖与super()扩展用法,以及Include包含页面和Macro宏定义与库调用方法,配合完整代码示例帮助开发者快速掌握模板引擎核心特性。
本文详细整理了Flask框架中Jinja2模板的常用语法,旨在为读者提供实用的参考指南。
1. 变量表示
{{ argv }}
在Jinja2模板中,变量通常用双大括号 {{ }} 包裹进行渲染。例如,代码片段展示了如何传递参数:
{% set links = [
('home',url_for('.home')),
('service',url_for('.service')),
('about',url_for('.about')),
] %}
对于列表或复杂数据结构,可以通过赋值操作进行预处理。示例代码展示了如何定义链接列表:
{% if not loop.first %}|{% endif %}
利用 for 循环可以遍历列表或字典,结合 loop.first 等内置变量控制输出格式,如分隔符的处理。
{% for label,link in links %}
{% if not loop.first %}|{% endif %}
<a href="{{ link }}" rel="external nofollow" >{{ label }}</a>
{% endfor %}
5. 定义测试函数
上述代码中的 loop.first 是一个内置的循环变量,用于判断是否为列表的第一项。此外,开发者也可以自定义测试函数来扩展模板功能。
自定义测试函数通常在 current_link 文件(如 Sample.py)中定义,而在 HTML 模板中通过特定的名称调用(此处为可选操作)。
@app.template_test('current_link')
def is_current_link(link):
return link == request.path
在 HTML 模板中调用自定义测试函数的示例代码如下:
<body>
{% set links = [
('home',url_for('.home')),
('service',url_for('.service')),
('about',url_for('.about')),
] %}
<nav>
{% for label,link in links %}
{% if not loop.first %}|{% endif %}
<a href="{% if link is current_link %}#
{% else %}
{{ link }}
{% endif %}
">{{ label }}</a>
{% endfor %}
</nav>
</body>

6. 块 (Block)
Flask 的强大之处之一在于其灵活的模板引用机制,使得页面布局管理变得非常便捷。
这里需要重点介绍 Block 的概念,它是模板继承的核心机制。
通常,模板文件放置在 templates 文件夹下。例如,我们新建一个名为 'base.html' 的文件作为基础模板。
在 base.html 中,通过定义多个 Block 占位符来编排整个页面的布局结构。
每个 Block 代表一段 HTML 代码块。这些块可以在当前的 base.html 中定义默认内容,也可以在被继承的子模板中重新定义。只要存在定义,块即可生效;若未定义,则显示默认内容或为空。
在子模板(如 home.html)中使用时,必须在文件顶部声明继承关系。如果 Python 代码渲染的是 home.html,而 home.html 又继承了 base.html,则必须使用 extends 语句明确继承链。
{% extends 'base.html' %}
Block 的定义格式如下:{% block 块名 %}...{% endblock (块名) %}。endblock 后的块名可以省略,但保留块名有助于提高代码结构的清晰度。
{% block 块名 %}
块内容
{% endblock (块名)%}
一旦在子模板中定义了同名 Block,base.html 中对应的默认块内容将被子模板的内容覆盖。
块的覆盖机制示例如下:
假设 base.html 中定义了 Block B 包含“内容1”,而在 home.html 中也定义了 Block B 包含“内容2”。此时,页面将优先显示“内容2”,因为子模板的内容覆盖了父模板的默认内容。
理解这一点很重要:base.html 作为通用模板可以直接引用,无需修改;但通过自定义 Block,我们可以灵活修改通用模板的局部内容,以满足特定页面的需求。
还有一种常见场景:我们既希望保留通用模板的内容,又希望在特定位置增加额外内容,而不是完全覆盖。
例如,在 base.html 中定义了 Footer 块:
<footer>
{% block footer %}
<p>Posted:Bikmin</p>
<p>Contact with:<a href="someone@example.com" rel="external nofollow" rel="external nofollow" >someone@example.com</a> </p>
{% endblock %}
</footer>
如果在子模板中不重新定义该块,则直接使用 base.html 中的通用模板内容,渲染效果如下:

如果希望保留原有模板内容,并在其上方添加一条水平线作为分隔符,该如何操作?
解决方法是在 home.html 中重新定义该 Block,并调用 super() 函数来保留父模板的内容。
{% block footer %}
<hr>
{{ super() }}
{% endblock %}
{{ super() }} 即 {{ super() }},它用于输出父模板中对应 Block 的原始内容。
需要注意的是,如果在同一个 HTML 文件中多次定义同一个 Block,后定义的会覆盖先定义的。
有时,我们希望在某个位置直接引用已定义的 Block 内容,而不必重新编写长串代码。此时可以使用自调用语法,无论 Block 在哪个 HTML 文件中定义,只要存在继承关系即可使用。
{{ self.块名() }}
7. 包含页面 (Include)
如果某些 HTML 代码片段频繁使用且固定不变,为了避免主 HTML 文档过于臃肿杂乱,可以将其单独提取。
将这些代码保存为独立的 HTML 模板文件,需要时再引入,有助于保持代码整洁。
{% include 'includes/_head.html' %}
使用 include 语句引入模板,引号内为文件路径。例如,'includes' 是 templates 下的一个子文件夹,路径需根据实际存放位置填写。
8. 宏 (Macro)
经过前面的学习,可以发现 Flask 中模板无处不在。仔细思考,Python 中的函数本质上也是一种“模板”:输入参数后执行特定功能。
因此,Jinja2 模板引擎自然也不缺少类似函数的功能——宏。
宏的定义示例如下:
下面定义了一个 input 标签的宏。通过宏,可以将参数修改为期望的默认值。调用时像使用普通函数一样,非常便捷。
{# 定义宏 #}
{% macro input(name,value='',type='text',size=20) %}
<input type="{{ type }}"
name="{{ name }}"
value="{{ value }}"
size="{{ size }}"/>
{% endmacro %}
宏的调用方式如下:
{{ input('username') }}
{{ input('password',type='password') }}
将宏集合为库
宏与 Python 函数类似,Python 函数可以封装在库中。同样,我们可以将多个宏集合在一个 HTML 文件中,使用时像调用库函数一样通过 import 引入。
答案是可以的。这种做法还有一个好处:使主 HTML 文件内容更加简练,节省空间,提高代码可读性。
下面举例将一个宏文件 '_macro.html' 引入到项目中。
那么如何将其引入到我们的模板文件中呢?
{% import '_macro.html' as ui %}
注意,必须使用 as 指定库名,否则在调用函数时无法区分来源。
调用方式也相应改变,如下所示:
{{ ui.input('username') }}
{{ ui.input('password',type='password') }}
这是否与 Python 中调用函数的语法完全一致?
小项目实战
#Sample.py 代码示例:
# coding:utf-8
from flask import Flask,render_template,request,url_for
app = Flask(__name__)
@app.route('/')
def home():
return render_template('home.html',title_name = 'welcome')
@app.route('/service')
def service():
return 'service'
@app.route('/about')
def about():
return 'about'
@app.template_test('current_link')
def is_current_link(link):
return link == request.path
if __name__ == '__main__':
app.run(debug=True)
#home.html 模板示例:
{% extends 'base.html' %}
{% import '_macro.html' as ui %}
{% block title %}{{ title_name }}{% endblock %}
{% block content %}
{% set links = [
('home',url_for('.home')),
('service',url_for('.service')),
('about',url_for('.about')),
] %}
<nav>
{% for label,link in links %}
{% if not loop.first %}|{% endif %}
<a href="{% if link is current_link %}#
{% else %}
{{ link }}
{% endif %}
">{{ label }}</a>
{% endfor %}
</nav>
<p>{{ self.title() }}</p>
{{ ui.input('username') }}
{{ ui.input('password',type='password') }}
{% endblock content %}
{% block footer %}
<hr>
{{ super() }}
{% endblock %}
#base.html 基础模板示例:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
{% include 'includes/_head.html' %}
{% endblock %}
</head>
<body>
<header>{% block header %}{% endblock %}</header>
<div>{% block content %}<p>hello</p>{% endblock %}</div>
{% for item in items %}
<li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}
<footer>
{% block footer %}
<p>Posted:Bikmin</p>
<p>Contact with:<a href="someone@example.com" rel="external nofollow" rel="external nofollow" >someone@example.com</a> </p>
{% endblock %}
</footer>
</body>
</html>
#_head.html 头部文件示例:
<meta charset="UTF-8">
<link href="{{ url_for('static',filename='site.css') }}" rel="external nofollow" rel="stylesheet">
<title>{% block title %}{% endblock %}</title>
#macro 宏定义示例:
{# 定义宏 #}
{% macro input(name,value='',type='text',size=20) %}
<input type="{{ type }}"
name="{{ name }}"
value="{{ value }}"
size="{{ size }}"/>
{% endmacro %}
运行项目后,访问对应路由即可看到效果。

更多关于 Python 相关内容可查看本站专题:《Python入门与进阶经典教程》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python文件与目录操作技巧汇总》
希望本文所述对大家 Python 程序设计有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









