本文最后更新于:2025年11月9日 晚上
在需要根据特定模板生成定制化文档的场景中,Word 模板是一种直观可靠的实现方式,本文通过将
json中的配置信息以表格的形式展示在Word的案例,介绍如何利用docxtpl和Jinja2这些Python库来实现基于现有的Word模板生成个性化的文档。
简介
我们的目标是构建一个带有多种格式配置、可编辑占位符的 Word 模板后,通过 Json 格式的信息将 Word 模板丰富成一个真正有意义的文档文件。
为此我们需要以下工作步骤:
- 构建通用、灵活、完备的 Word 模板
- 为模板组织相应的数据
- 调用 Python 脚本,将数据插入到模板中生成 Word 文件
- 将 Word 文件转换为 PDF
Jinja2
Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全:
- 官方网站:https://docs.jinkan.org/docs/jinja2/
- 可以参考这篇介绍:https://www.zywvvd.com/notes/coding/doc/jinja2/jinja2/
我们需要在 Word 模板中加入 Jinja2 的代码。
docxtpl
正常的Jinja2语法只有%的普通标签,而docxtpl的类语法包含%p,%tr,%tc,%r:
1 | |
通过使用这些标记,python-docx-template将真正的Jinja2标记放入文档的XML源代码中的正确位置。
PS:这四种标签,起始标签不能在同一行,必须在不同的行上面,否则无法正确渲染。
例如:
1{%p if display_paragraph %}Here is my paragraph {%p endif %}需改写成:
1
2
3{%p if display_paragraph %}
Here is my paragraph
{%p endif %}
- pip 安装:
1 | |
- conda 安装:
1 | |
- 使用:
1 | |
模板构建、使用流程
合并单元格
- 水平合并单元格
在for循环中要合并的单元格内容前面补充:
1 | |
- 垂直合并单元格
在for循环中要合并的单元格内容前面补充:
1 | |
Word文档模板
我们需要创建一个包含占位符的Word文档模板 (docs 格式)。这些占位符将在后续的文档生成过程中被实际内容替换。使用 Jinja2 的模板语法,我们可以定义占位符和可替换的内容。例如,可以使用 {{ name }} 表示一个占位符。
这里我给出一个我随便生成的一个模板
是在 Linux 下 LibreOffice Writer 生成的 docx 文件,windows 打开可能会有乱码。

数据准备
需要准备根据模板中的字段信息匹配的 Json 数据(字典)
1 | |
渲染文档
使用 docxtpl 和 Jinja2 来将数据填充到文档模板中,并生成最终的文档。
首先,我们需要加载模板文件并创建一个DocxTemplate对象。然后,我们将数据传递给模板对象,使用render方法渲染文档。最后,可以选择将文档保存到本地文件或直接进行下载。
针对上文中的模板文件,提供以下示例代码:
需要准备一张
test.png图片
1 | |
效果展示
上述流程会生成一个 Word 文件 和一个 PDF 文件

多模板拼接
若最终生成的 Word 是由多个.docx模板拼接而成,可以使用下述代码:
1 | |
进阶用法
数学运算
模板中支持如下运算:
算术运算
+:加法{{ a + b }}-:减法{{ a - b }}*:乘法{{ a * b }}/:除法{{ a / b }}(结果是浮点数)//:整除{{ a // b }}(结果是整数)%:取模{{ a % b }}**:幂运算{{ a ** 2 }}
比较运算 (常用于 if 语句)
==:等于!=:不等于>:大于>=:大于等于<:小于<=:小于等于
逻辑运算 (常用于 if 语句)
andornot( ):用于改变优先级
其他常用操作
- 字符串连接:
{{ "Hello " + name }} - 列表/元组索引:
{{ my_list[0] }} - 字典键值访问:
{{ my_dict['key'] }}- 或
{{ my_dict.key }}(如果键是有效的标识符)
- 获取属性:
{{ obj.attribute }} - 函数调用 (需在上下文中传入函数):
{{ get_full_name(first, last) }} - 三元表达式:
{{ "Yes" if condition else "No" }}
数据填入 a b 即可计算出 a/b
虽然 Jinja2 支持这些运算,但模板的主要职责是展示,复杂的业务逻辑最好在 Python 代码中处理完毕,然后将结果通过
context传入模板,以保持模板的简洁和可读性。
自定义过滤器
模板渲染过程中可以自定义函数来处理数据,大大增加模板灵活性。
函数为 Python 中定义:
1 | |
模板的用法:
过滤器的第一个参数为 | 左边的变量,如果需要输入其他参数,可以在函数后面追加其他变量。
- 示例:
过滤器
1 | |
多元素操作
这里以求和操作为例,列举多种多元素操作方式。
内置过滤器
jinja2 拥有 sum 基础过滤器,可以用于多元素处理
- 模板代码
1 | |
- Python 代码
1 | |
for 循环
如果需要更复杂的求和逻辑,可以使用循环和自定义变量。
-
模板代码
在 Jinja2 中,
{% set %}语句在循环内部创建的是局部变量,而不是修改外部作用域的变量需要通过创建一个命名空间对象,确保我们在修改的是同一个变量。
1 | |
自定义过滤器
自定义 Python 函数:
1 | |
- 模板代码
效果测试
1 | |
- Python 代码
1 | |
- 生成效果

问题填坑
多行合并表格渲染异常
我遇到过 vm 表格渲染异常的状况,代码没有问题,渲染出来只有 3 行,而且 vm 合并列异常(只有2行)
问题定位到是表格格式的问题
- 解决方案:选中所有表格,清楚直接格式即可。
参考资料
- https://docs.jinkan.org/docs/jinja2/
- https://docxtpl.readthedocs.io/en/latest/
- https://juejin.cn/post/7294476268505595931
- https://blog.csdn.net/bobocqu/article/details/141690779
- https://blog.csdn.net/viviliving/article/details/106314758
- https://blog.csdn.net/heianduck/article/details/121726208
“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”
微信支付
支付宝支付