Flask Jinja2模板核心语法详解:变量、块、宏与包含

林舟
林舟
发布时间:2026-10-13 | 6人浏览过
原创

本文系统总结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 程序设计有所帮助。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表