{% extends %} 和 {% block %} 是怎么把几层模板拼成一个页面的?{{ block.super }} 取的是哪一层?加载模板要读几次盘?这篇用三层模板和一个带日志的加载器把这些都摊开。
base → [base-top]base-title|base-content|base-footer[base-bottom] mid → [base-top]mid-title/base-title|mid-content(mid-inner)|base-footer[base-bottom] leaf → [base-top]mid-title/base-title|leaf-content/mid-content(leaf-inner)|base-footer[base-bottom] leaf2 → [base-top]base-title|c2|base-footer[base-bottom]
渲染从最子的模板开始:它 extends 的链一路向上,直到根模板;最后根模板被渲染,遇到 block 时取链上「最子的」那个定义。
leaf.html 里定义了 nosuch block(父模板没有):输出里出现 IGNORED 吗 → False
{% extends %} 前面有文字: text before [base-top]base-title|base-content|base-footer[base-bottom]
同一个模板里定义两个同名 block: TemplateSyntaxError: Template: <实验目录>拼错 block 名是常见 bug:子模板的内容因此被静默忽略,页面上看不到——排查时先核对 block 名。
extends 变量: [base-top]base-title|dyn|base-footer[base-bottom] 渲染 base.html 加载: ['base.html'] 渲染 mid.html 加载: ['mid.html', 'base.html'] 渲染 leaf.html 加载: ['leaf.html', 'mid.html', 'base.html'] (三层继承 = 三次读盘;cached 加载器会缓存)
这是 filesystem 加载器的读盘计数(手工在加载器的 get_contents 上加了日志)。
with_inc.html → [base-top]base-title|inc(1|inc-block)|base-footer[base-bottom] 加载: ['with_inc.html', 'base.html', 'inc.html'] inc.html 里的 block b 被外层 extends 覆盖了吗:输出仍是 inc-block → True
选择:「页面骨架 + 可替换区域」用 extends;「可复用的片段」用 include(带参数用 with,隔离用 only,后者本文没有测)。
base.html 5.3 µs leaf2.html 10.8 µs leaf.html 21.5 µs
合成模板,渲染很小;真实页面的开销主要在数据库和你的变量。