(八)继承、包含与宏的组合过程
多个页面共用页头和主体位置,外层页面留一个 block,子页面填入内容。先从一个小页面观察三种组合。
<!-- 项目文件:demos/templates/demo_base.html -->
<!doctype html>
<html lang="zh-CN"><meta charset="utf-8">
<title>{% block title %}阅读书架{% endblock %}</title>
<header>我的阅读记录</header>
<main>{% block content %}{% endblock %}</main>
</html>block title 和 block content 分别留下标题与正文的位置。子页面使用 extends 指定这份骨架:
<!-- 项目文件:demos/templates/demo_panel.html -->
{% extends 'demo_base.html' %}
{% from '_demo_macros.html' import reading_status %}
{% block title %}{{ book.title }}{% endblock %}
{% block content %}
{% include '_demo_item.html' %}
{{ reading_status(book.finished) }}
{% endblock %}include 把另一份模板放在当前位置,并可读取当前位置的数据;from ... import 引入模板宏。下面两份短模板分别生成书名和状态。
<!-- 项目文件:demos/templates/_demo_item.html -->
<!-- include 直接读取调用位置的 book 变量。 -->
<h1>{{ book.title }}</h1><!-- 项目文件:demos/templates/_demo_macros.html -->
{% macro reading_status(finished) -%}
<span>{{ '已读' if finished else '未读' }}</span>
{%- endmacro %}宏 reading_status(finished) 像带参数的函数,接收布尔值并生成标记。'已读' if finished else '未读' 沿用条件表达式的读法;-%} 和 {%- 去掉控制语句旁多余的空白,改变排版空白,不改变判断逻辑。
# 项目文件:demos/inheritance_demo.py
from flask import Flask, render_template
app = Flask(__name__)
@app.get("/")
def index():
# 数据仍来自已经会写的普通字典,先观察模板怎样组合。
return render_template(
"demo_panel.html", book={"title": "Python Web", "finished": False}
)
if __name__ == "__main__":
page = app.test_client().get("/")
print(page.status_code, "Python Web" in page.text, "未读" in page.text)执行 uv run python ../demos/inheritance_demo.py,输出 200 True True。这次渲染先取得骨架,替换标题与主体,在主体中包含书名,再调用状态宏生成“未读”。完整书架也会用同样方式组合导航、消息、表单和列表。