4. Jinja2模板引擎:模板语法基础、变量与过滤器、控制结构(if/for)、模板继承与宏
好,咱们今天聊聊Jinja2。说实话,在搭建法律文书自动生成系统时,Jinja2是我最依赖的伙伴之一。它就像文书的「骨架」,把数据和格式完美地粘合在一起。你想想看,一份判决书,事实认定、法律依据、判决结果都是动态的,但结构是固定的——Jinja2就是干这个的。
4.1 模板语法基础
Jinja2的语法,说白了就三种「标记」:
- 变量:用
{{ ... }}包裹,比如{{ 当事人姓名 }} - 语句:用
{% ... %}包裹,比如{% if 性别 == '男' %} - 注释:用
{# ... #}包裹,不会出现在最终文档里
我刚开始用的时候,老把变量和语句搞混。后来记住一个诀窍:变量是「输出」东西,语句是「做」事情。嗯,这样就好记多了。
{# 这是一个典型的法律文书模板片段 #}
{{ 法院名称 }}
{{ 案号 }}
当事人:{{ 原告姓名 }}({{ 原告性别 }})
dangshiren_xingming 比 dsrxm 好维护得多。我在项目里吃过这个亏,后来重构时改得想哭。
4.2 变量与过滤器
变量就是数据,过滤器就是「加工」数据的工具。Jinja2内置了很多好用的过滤器,我挑几个法律文书里常用的说说:
| 过滤器 | 作用 | 示例 |
|---|---|---|
default |
设置默认值 | {{ 被告姓名 | default('未知') }} |
upper |
转大写 | {{ 法院名称 | upper }} |
date |
格式化日期 | {{ 立案日期 | date('Y年m月d日') }} |
join |
拼接列表 | {{ 证据清单 | join('、') }} |
过滤器可以链式调用,比如:{{ 当事人姓名 | default('未知') | upper }}。不过我个人建议别链太多,超过两个就有点难读了。
default 过滤器。结果有一条记录立案日期是空的,模板直接报错,整个文书生成流程卡住了。从那以后,所有可能为空的字段我都加上了默认值。
4.3 控制结构:if/for
控制结构是模板的「大脑」。没有它,模板就是死板的填空。有了它,模板才能「思考」。
4.3.1 if 条件判断
法律文书里经常需要根据条件输出不同内容。比如:
{% if 判决结果 == '支持' %}
本院予以支持。
{% elif 判决结果 == '部分支持' %}
本院予以部分支持。
{% else %}
本院不予支持。
{% endif %}
你想想看,如果没有if,你得写三个不同的模板,多麻烦。Jinja2一个模板就搞定了。
4.3.2 for 循环
法律文书里经常有「证据清单」、「法律依据列表」这种重复结构。for循环就是干这个的:
证据清单:
{% for 证据 in 证据列表 %}
{{ loop.index }}. {{ 证据.名称 }}({{ 证据.类型 }})
{% endfor %}
这里有个小细节:loop.index 是Jinja2内置的循环变量,从1开始计数。还有 loop.first、loop.last 可以判断首尾元素。我在生成「合议庭成员」列表时经常用 loop.last 来控制逗号和「和」字的输出。
4.4 模板继承与宏
这部分是我觉得Jinja2最强大的地方。说白了,就是「复用」。
4.4.1 模板继承
法律文书有很多共同结构:页眉、页脚、法院名称、案号格式。你难道要每个模板都写一遍?当然不。
先写一个「基模板」:
<!-- base.html -->
<div class="header">
{{ 法院名称 }}
<hr>
</div>
{% block 正文 %}{% endblock %}
<div class="footer">
本判决书一式{{ 份数 }}份
{% endblock %}
然后「子模板」继承它:
{% extends "base.html" %}
{% block 正文 %}
<p>原告:{{ 原告姓名 }}</p>
<p>被告:{{ 被告姓名 }}</p>
<p>案由:{{ 案由 }}</p>
{% endblock %}
这样,页眉页脚只需要维护一份。我见过有人把20多份文书模板都写成独立的,结果法院名称改了,要改20个文件。用继承,改一个就行。
4.4.2 宏
宏就像函数,把重复的HTML片段封装起来。比如法律文书里经常要写「当事人信息」:
{% macro 当事人信息(姓名, 性别, 出生日期, 住址) %}
<p>姓名:{{ 姓名 }}</p>
<p>性别:{{ 性别 }}</p>
<p>出生日期:{{ 出生日期 | date('Y年m月d日') }}</p>
<p>住址:{{ 住址 }}</p>
{% endmacro %}
使用时:
{{ 当事人信息(原告姓名, 原告性别, 原告出生日期, 原告住址) }}
嗯,这里要注意:宏的参数顺序要固定,不然容易传错。我建议用关键字参数,虽然写起来长一点,但可读性好很多。
macros.html,然后在需要的地方用 {% import "macros.html" as 宏 %} 导入。这样模板文件会非常干净。
4.5 知识体系结构图
下面这张图是我梳理的Jinja2模板引擎核心知识体系,你可以对照着看:
这张图把Jinja2的四个核心模块串起来了。你从中心出发,沿着分支走一遍,基本就能掌握全貌。
公众号:蓝海资料掘金营,微信deep3321