在这里插入图片描述
简介:在 Flask 开发中,Jinja2 模板引擎的继承机制是提升开发效率和代码可维护性的关键工具。 本文将带你深入了解 Jinja2 模板继承的核心功能,从基础概念到实际应用,帮助你掌握如何通过模板继承构建高效且可复用的代码结构。我们不仅会探讨如何定义父模板子模板,还会通过实际案例展示如何在多页面布局动态内容加载组件化开发中灵活应用模板继承。

目录

一、Jinja2模板的继承机制
1.1 模板继承的基本概念
1.2 如何定义父模板
1.3 如何定义子模板
二、Jinja2模板继承的功能使用案例
2.1 基础模板继承
2.2 添加动态内容
2.3 覆盖父模板内容
三、Jinja2模板集成的应用场景
3.1 多页面布局
3.2 动态内容加载
3.3 组件化开发
四、结束语


🚀 读完本文,你将解锁以下超实用技能和知识储备:

  • 🔗 理解 Jinja2 模板的继承机制:掌握如何通过模板继承,构建高效且可复用的代码结构
  • 🛠️ 掌握 Jinja2 模板中的控制语句:学会在模板中灵活运用动态内容的展示。
  • 🌟 学会在实际项目中应用模板继承:将理论知识转化为实际操作,提升项目开发效率。
  • 💡 提升 Flask + Jinja2 开发效率和代码可维护性:通过模板继承,让你的代码更加简洁易于维护

一、Jinja2模板的继承机制

1.1 模板继承的基本概念

在 Flask 开发中,Jinja2 模板引擎提供了强大的模板继承功能。模板继承允许你定义一个 父模板,并在其中定义可被子模板覆盖的 块(blocks)。子模板可以继承父模板的结构,同时覆盖扩展父模板中的特定部分。这种方式可以显著减少模板代码的重复,提高开发效率。基本语法如下:

1.2 如何定义父模板

父模板是模板继承的基础,它定义了页面的整体结构和布局。以下是一个简单的父模板示例:

<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
        <h1>我的网站</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于我们</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>

在父模板中,我们定义了两个块:title 和 content。这些块允许在子模板中被覆盖。

1.3 如何定义子模板

子模板通过 extends 语句继承父模板,并可以覆盖父模板中的块。以下是一个子模板的示例:

<!-- index.html -->
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
<h1>欢迎来到首页</h1>
<p>这里是首页的内容。</p>
{% endblock %}

在这个子模板中,我们覆盖了父模板中的 titlecontent 块,从而实现了页面内容的定制。注意,子模板与父模板需要在同级目录下,否则需要在继承位置中添加父模板的相对路径。同时,子模板中,每个块(blocks)需要前后对应,以{% blockname %} 内容 {% endblock %}的格式进行框定

二、Jinja2模板继承的功能使用案例

2.1 基础模板继承

基础模板继承是模板继承的核心功能。通过继承父模板,子模板可以复用父模板的结构,同时覆盖扩展特定部分。以下是一个完整的示例:

  • Flask后端代码:
# -*- coding: utf-8 -*-
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)
# 定义自定义过滤器
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
    return value.strftime(format)

# 注册过滤器
app.jinja_env.filters['datetimeformat'] = datetimeformat
@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run()

  • 父模板(base.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
    	<h1>头部header</h1>
        <h1>我的网站,我来自父模板</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于父模板</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
    	<h1>尾部footer</h1>	
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>
  • 子模板(index.html):
{% extends "base.html" %}

{% block title %}首页 - 子模板的网站{% endblock %}

{% block content %}
<h1>欢迎来到子模板的首页</h1>
<p>这里是子模板的内容。</p>
{% endblock %}
  • 渲染结果:
    在这里插入图片描述

2.2 添加动态内容

模板继承中,你可以在子模板中添加动态内容。以下是一个示例,展示如何在子模板中使用 Flask 传递的变量

  • Flask 后端代码:
# -*- coding: utf-8 -*-
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)
# 定义自定义过滤器
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
    return value.strftime(format)

# 注册过滤器
app.jinja_env.filters['datetimeformat'] = datetimeformat
@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.now())

if __name__ == '__main__':
    app.run()

  • 子模板(index.html):
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
<h1>欢迎来到首页</h1>
<p>当前时间:{{ current_time | datetimeformat}}</p>
{% endblock %}

2.3 覆盖父模板内容

你可以在子模板中完全覆盖父模板的块,也可以在父模板的基础上扩展内容。以下是一个扩展内容的示例

  • 父模板(base.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
    	<h1>头部header</h1>
        <h1>我的网站,我来自父模板</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于父模板</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
    	<h1>尾部footer</h1>	
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>
  • 子模板(index.html):
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
<h1>欢迎来到首页</h1>
<p>这里是首页的内容。</p>
{% endblock %}
  • 渲染结果:
    在这里插入图片描述

三、Jinja2模板集成的应用场景

3.1 多页面布局

模板继承非常适合多页面布局。你可以定义一个通用的父模板,然后为每个页面创建一个子模板。这样可以避免重复编写公共部分的代码,提高开发效率,便于维护。

- Flask后端代码:

# -*- coding: utf-8 -*-
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)
# 定义自定义过滤器
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
    return value.strftime(format)

# 注册过滤器
app.jinja_env.filters['datetimeformat'] = datetimeformat
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/about')
def aboutx():
    return render_template('about.html')

if __name__ == '__main__':
    app.run()


  • 父模板(base.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
    	<h1>头部header</h1>
        <h1>我的网站,我来自父模板</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于父模板</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
    	<h1>尾部footer</h1>
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>
  • 子模板-1(index.html):
{% extends "base.html" %}

{% block title %}首页 - 子模板的网站{% endblock %}

{% block content %}
<h1>欢迎来到子模板的首页</h1>
<p>这里是子模板的内容。</p>
{% endblock %}
  • 子模板-2(about.html):
{% extends "base.html" %}

{% block title %}关于我们 - 我的网站{% endblock %}

{% block content %}
<h1>关于我们,子模板-2的网站</h1>
<p>这里是关于我们页面的内容。</p>
{% endblock %}
  • 渲染结果:
    在这里插入图片描述

3.2 动态内容加载

模板继承可以方便地加载动态内容。通过在父模板中定义块,并在子模板中覆盖这些块,你可以实现动态内容的加载。

  • Flask后端代码:
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', current_time=datetime.now())

if __name__ == '__main__':
    app.run()
  • 父模板(base.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
    	<h1>头部header</h1>
        <h1>我的网站,我来自父模板</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于父模板</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
    	<h1>尾部footer</h1>
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>
  • 子模板(index.html):
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
<h1>欢迎来到首页</h1>
<p>当前时间:{{ current_time | datetimeformat}}</p>
{% endblock %}
  • 渲染结果:
    在这里插入图片描述

3.3 组件化开发

模板继承支持组件化开发。你可以将页面的不同部分定义为独立的模板块,然后在子模板中组合这些块。这种方式可以提高代码的可维护性和可复用性。

  • Flask后端代码:
# -*- coding: utf-8 -*-
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)
# 定义自定义过滤器
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
    return value.strftime(format)

# 注册过滤器
app.jinja_env.filters['datetimeformat'] = datetimeformat
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/about')
def aboutx():
    return render_template('about.html')

if __name__ == '__main__':
    app.run()
  • 父模板(base.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}默认标题{% endblock %}</title>
</head>
<body>
    <header>
    	<h1>头部header</h1>
        <h1>我的网站,我来自父模板</h1>
        <nav>
            <ul>
                <li><a href="/">首页</a></li>
                <li><a href="/about">关于父模板</a></li>
            </ul>
        </nav>
    </header>
    <main>
        {% block content %}
        <p>这是默认内容。</p>
        {% endblock %}
    </main>
    <footer>
    	<h1>尾部footer</h1>
        <p>&copy; 2025 我的网站</p>
    </footer>
</body>
</html>
  • 子模板-1(index.html):
{% extends "base.html" %}

{% block title %}首页 - 我的网站{% endblock %}

{% block content %}
<h1>关于我们,子模板-1的网站</h1>
<p>这里是关于我们页面的内容。</p>
{% endblock %}
  • 子模板-2(about.html):
{% extends "base.html" %}

{% block title %}关于我们 - 我的网站{% endblock %}

{% block content %}
<h1>关于我们,子模板-2的网站</h1>
<p>这里是关于我们页面的内容。</p>
{% endblock %}
  • 渲染结果:
    在这里插入图片描述

四、结束语

通过本文的介绍,你已经掌握了 Jinja2 模板的继承机制,并学会了如何在实际项目中应用模板继承。模板继承不仅可以减少模板代码的重复,还可以提高代码的可维护性和可复用性。希望这些知识能够帮助你在 Flask 开发中更加高效地构建高质量的 Web 应用。

如果你对 Jinja2 模板继承有更多问题,或者在实际开发中遇到了困难,欢迎在评论区留言,我会尽力为你解答


最后,感谢你的阅读!如果你觉得本文对你有帮助,不妨点赞和关注,我会继续分享更多关于 Python 和 Flask 开发的实用知识。🚀

关注专栏每周更新,带你从“第一个 Flask 项目”一路进阶到“Docker 部署、JWT 鉴权、微服务拆分”。

版权归作者所有,未经许可请勿抄袭,套用,商用(或其它具有利益性行为)。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐