学习目标
- 使用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