学习目标
- 使用jinja2模板的递归方法重构报告生成模板
前期设置
- 初始化document
- 定义直接显示jinja2渲染结果的函数render_templ
Recursive Example For Jinja2
首先我们来看一个Jinja2模板的递归例子,需要注意此时的渲染方式有变化,需要提前设置环境。
import jinja2
template = """
{%- set idxs = [0] -%}
{%- for item in sitemap recursive %}
depth={{idxs|length}}. idx={{loop.index}}. pidx={{idxs[-1]}}. title={{item.title}}
{%- if item.children -%}
{%- do idxs.append(loop.index) -%}
{{ loop(item.children) }}
{%- do idxs.pop() -%}
{%- endif %}
{%- endfor %}
"""
class Node():
def __init__(self, title, children=[]):
self.title = title
self.children = children
sitemap = [
Node('a', [
Node('a_a', [
Node('a_a_a'),
]),
Node('a_b', [
Node('a_b_a', [
Node('a_b_a_0'),
]),
]),
]),
Node('b'),
]
env = jinja2.Environment(extensions=['jinja2.ext.do'])
print(env.from_string(template).render(sitemap=sitemap))
depth=1. idx=1. pidx=0. title=a
depth=2. idx=1. pidx=1. title=a_a
depth=3. idx=1. pidx=1. title=a_a_a
depth=2. idx=2. pidx=1. title=a_b
depth=3. idx=1. pidx=2. title=a_b_a
depth=4. idx=1. pidx=1. title=a_b_a_0
depth=1. idx=2. pidx=0. title=b
把之前生成报告的模板改为使用递归的形式
而我们的Docoment类同样是一个树结构,可以进行递归的模板生成。而且每个Chapter和SubChapter都有着类似的结构,可以使用同样的处理方式,所以可以把我们之前的jinja2模板改为:
<body>
<section class = "rich-text">
<h1>{{ document.title }}</h1>
<p>{{ document.foreword }}</p>
{% for chapter in document.chapters recursive %}
{%- if not chapter.title is none %}
<h2>{{ chapter.title }}</h2>
{%- endif -%}
{%- if not chapter.foreword is none %}
<p>{{ chapter.foreword }}</p>
{%- endif -%}
{% if not chapter.table is none %}
{% set table = chapter.table %}
<table>
<tr class='chapter_table'>
{% for column in table.columns %}
<th>{{column}}</th>
{% endfor %}
</tr>
{% for index in table.index %}
<tr>
{% for column in table.columns %}
<td>{{ table[column][index] }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endif %}
{% if not chapter.image is none %}
{% set image = chapter.image %}
<div><img src="{{ image }}"></div>
{% endif %}
{% if not chapter.content is none %}
<p>{{ chapter.content }}</p>
{% endif %}
{% if chapter.chapters.__len__() > 0 %}
{{ loop(chapter.chapters) }}
{% endif %}
{% endfor %}
</section>
</body>
作业
上面的递归会把所有的章标题记录为<h2>
,对于更深一层的子章节我们需要使用更小的标签,比如<h3>
,这时候就可以使用递归深度来做规定。请自行做出作为练习。
想要直接查看结果可以参照Example_3