bigywater.tech
Flask · 53

模板继承与 Block

{% extends %} 与 {% block %} 到底怎么工作?super() 取的是什么?block 里为什么看不到循环变量?继承层数多了会不会慢?这篇用最小的模板把每个规则渲染一遍。

scoped
让 block 能读到循环变量的修饰
23.4 µs
10 层继承的一次渲染耗时
忽略
子模板里写在 block 之外的内容的下场

基本继承与 super()

实测 · 本机执行输出
  [base.html] <html>
     <title>{% block title %}默认标题{% endblock %}</title>
     <body>
     {% block content %}基础内容{% endblock %}
     <footer>{% block footer %}© base{% endblock %}</footer>
     </body></html>
  [child.html] {% extends "base.html" %}
     {% block title %}子页面 - {{ super() }}{% endblock %}
     {% block content %}<h1>{{ heading }}</h1>{% endblock %}
  渲染 child.html → '<html>\n<title>子页面 - 默认标题</title>\n<body>\n<h1>你好</h1>\n<footer>© base</footer>\n</body></html>'

上一篇:Flask 模板搜索路径;下一篇:Context Processor。

多级继承

实测 · 本机执行输出
  渲染 grand.html → '<html>\n<title>子页面 - 默认标题</title>\n<body>\n<h1>你好</h1><p>孙页面追加</p>\n<footer>孙页脚|© base</footer>\n</body></html>'

嵌套 block

实测 · 本机执行输出
  nested_child → '[外 内被覆盖]'
  只有文字的子模板 → '<html>\n<title>默认标题</title>\n<body>\n基础内容\n<footer>© base</footer>\n</body></html>'

循环里的 block

实测 · 本机执行输出
  没有 scoped: '子 未定义|子 未定义|'
  scoped     : '子 1|子 2|'

self.block

实测 · 本机执行输出
   '<title>页面</title><h1>页面</h1>'

动态继承

实测 · 本机执行输出
  layout='alt_layout.html'  → '<main>动态布局内容</main>'
  layout='base.html'        → '<html>\n<title>默认标题</title>\n<body>\n动态布局内容\n<footer>© base</footer>\n</body></html>'
  layout 缺失 → UndefinedError: 'layout' is undefined

extends 的位置与 include

实测 · 本机执行输出
  extends 前面有文字(不会报错,文字照样输出): 前面有文字\n<html>\n<title>默认标题</title>\n<body>\n基础内容\n<footer>© base</footer>\n</body></ht
  子模板里 {% set %} 对父模板: '[子里 set]b:子里 set' (子模板顶层的 set 在父模板渲染前执行,父模板读到了它)
  include 默认带 context;without context 看不到 v;ignore missing 跳过缺失: '主<1>|<无v>|'

继承的成本

实测 · 本机执行输出
   0 层继承:渲染 3.7 µs
   3 层继承:渲染 9.7 µs
  10 层继承:渲染 23.4 µs

分步演示

模板继承
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:{% import %} 与继承的交互、{% block %} 的 required 修饰(Jinja 3.1 新增)、异步模板、宏在子模板 block 里的作用域
    京ICP备2026067502号-1京公网安备11010502063487号