台湾省网站建设_网站建设公司_GitHub_seo优化
2026/1/19 18:53:55 网站建设 项目流程

python-docx库的核心功能是程序化创建全新的Word文档,但在基于已有模板替换其部分内容时,其操作会非常繁琐。用户需要先解析文档结构、定位具体位置、手动替换内容,并维护原有格式与布局,导致开发效率较低。相关使用方法可参考:基于python-docx库的Word文档自动处理全解。

python-docx-template正是为解决这一痛点而设计的。它借鉴Jinja2模板引擎的思路,允许在Word文档中直接插入类似{{variable}}的占位符,随后仅用几行代码即可完成数据填充,无需关心底层文档结构,完美适配基于模板修改文档的场景。

python-docx-template基于python-docx实现文档读写功能,并借助jinja2提供灵活的模板标签支持,其设计思路如下:

  1. 用Word制作模板
    在Microsoft Word中自由设计文档格式,如插入图片、设置页眉页脚、调整表格样式,充分利用Word强大的排版功能。

  2. 插入模板变量
    在需要动态内容的位置,直接输入Jinja2风格的标签,例如{{company_name}}{%for item in list%}

  3. 保存为模板文件
    将文档保存为普通的.docx文件,该文件即成为可复用的模板。

  4. 用Python批量生成
    加载模板并传入字典或对象,python-docx-template会自动替换标签,生成最终文档。

python-docx-template的官方代码仓库地址为:python-docx-template,详细文档可参阅:python-docx-template doc。本文使用的python-docx-template版本为0.20.2,安装命令如下:

pip install docxtpl

其中,docxtpl是python-docx-template库的正式分发名称,二者指代同一工具。

目录
  • 1 使用说明
    • 1.1 核心概念
      • 1.1.1 标签说明
      • 1.1.2 常见元素
    • 1.2 复杂元素
      • 1.2.1 富文本
      • 1.2.2 富文本段落
      • 1.2.3 浮动对象
      • 1.2.4 子文档
    • 1.3 补充操作
      • 1.3.1 转义操作
      • 1.3.2 获取未定义变量
      • 1.3.3 Jinja自定义过滤器
      • 1.3.4 Microsoft Word 2016特殊行为说明
  • 2 参考

1 使用说明

1.1 核心概念

1.1.1 标签说明

python-docx-template允许在Word文档中使用Jinja2标签和过滤器。但为确保其在Word中正常运作,需遵循若干限制。

常规Jinja2标签仅能在同一段落内且同一文本运行中使用,若需控制段落、表格行或包含样式的完整文本运行,则必须使用后续章节介绍的复杂元素标签语法。

举例而言,若创建一个所有字符样式相同的段落,Word内部只会生成一个文本运行对象。但若在该段落中将部分文字设置为加粗,Word会将原有文本运行拆分为三个独立部分,分别对应普通样式、加粗样式及恢复后的普通样式。

标签

若要对段落、表格行、表格列以及文本段进行管理,需使用以下专用语法:

  • 段落标签:{%p jinja2_tag %}
  • 表格行标签:{%tr jinja2_tag %}
  • 表格列标签:{%tc jinja2_tag %}
  • 文本段标签:{%r jinja2_tag %}

这些以{% %}包裹的内容是Jinja2模板语法标签,引擎会识别并执行其中的逻辑。一个完整的模板标签基本结构如下:

{% 指令关键字 参数/条件 %}  // 起始标签
内容                      // 被标签控制的文本
{% 结束关键字 %}          // 结束标签

通过此类标签,python-docx-template可自动将标准Jinja2标签,即去除前缀ptrtcr后的内容,精确嵌入到文档XML源码的相应位置。

假设模板内容如下:

{%p if display_paragraph %}
一段或多段文本内容
{%p endif %}

无论display_paragraph变量取值如何,首尾两个包含{%p ... %}标签的段落,都不会出现在最终生成的docx文档中。
只有当display_paragraph的值为True时,以下内容才会被保留在生成的文档里:

一段或多段文本内容

对于模板里的标签格式需遵循如下要求,否则无法生成正确结果:

  • 起始标签分隔符后必须加空格,结束标签分隔符前必须加空格:
    • 错误示例:
      {%if something%}
      {%pif display_paragraph%}
      
    • 正确示例:
      {% if something %}
      {%p if display_paragraph %}
      
  • 同一段落、行、列或文本段内,禁止连续使用标签分隔符:
    • 错误示例:
      {%p{%tr{%tc{%r
      
  • 标签与内容不可写在同一行,需换行排版:
    • 错误示例:
      {%p if display_paragraph %}Here is my paragraph {%p endif %}
      
    • 正确示例:
      {%p if display_paragraph %}
      Here is my paragraph
      {%p endif %}
      

1.1.2 常见元素

显示变量

Jinja2模板里,可以用双大括号来显示变量:

{{ <变量名> }}

如果变量是普通字符串,字符串里的特殊符号会自动转换成对应的格式:

  • \n → 换行
  • \a → 分段
  • \t → 制表符(按一下 Tab 键的效果)
  • \f → 分页符

如果变量是富文本(RichText)对象,必须在变量名前加一个r,明确表示要渲染这个富文本内容:

{{r <变量名> }}

注意,r要紧跟在左大括号的后面。

此外,变量名中禁止直接使用<,>, &这类字符,除非用了转义语法。

注释

可以在模板中添加类Jinja2风格的注释,注释不会被渲染到最终文件:

{#p 这是一个段落类型的注释 #}
{#tr 这是一个表格行类型的注释 #}
{#tc 这是一个表格单元格类型的注释 #}

在执行如下代码对模板文件进行渲染操作时,模板中原有的所有注释信息均会被清除,不会保留在最终的渲染结果中:

# https://github.com/elapouya/python-docx-template/blob/master/tests/comments.py
from docxtpl import DocxTemplate
import os# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/comments_tpl.docx
tpl = DocxTemplate("templates/comments_tpl.docx")tpl.render({})
os.makedirs("output",exist_ok=True)
tpl.save("output/comments.docx")

文本的拆分与合并

若包含Jinja2标签的文本过长,会导致可读性下降,例如:

我的房子位于{% if living_in_town %}城市区域{% else %}乡村地区{% endif %},我非常喜欢它。

借助{%-语法,可将Jinja2标签与上一行内容合并,同时借助-%}语法,可将Jinja2标签与下一行内容合并。此时可使用回车键(Enter)或Shift+Enter对文本进行拆分排版,再通过上述的标签语法将拆分后的内容合并为一个整体,示例如下:

我的房子位于
{%- if living_in_town -%}
城市区域
{%- else -%}
乡村地区
{%- endif -%}
,我非常喜欢它。

渲染代码如下:

from docxtpl import DocxTemplate
tpl = DocxTemplate("template.docx")
context = {"living_in_town": True}tpl.render(context)
tpl.save("output/output.docx")

表格

可以使用colspan标签实现表格单元格的水平合并:

{% colspan <var> %}

<var>必须为整数,用于指定需要合并的列数。也可通过Jinja2模板引擎自动计算,如内置过滤器count通过管道符|接收col_labels,用于统计其元素数量:

{% colspan col_labels|count %}

以下示例展示了如何利用colspan标签、trtc标签动态填充一个表格:

# https://github.com/elapouya/python-docx-template/blob/master/tests/dynamic_table.py
from docxtpl import DocxTemplate
import os
# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/dynamic_table_tpl.docx
tpl = DocxTemplate("templates/dynamic_table_tpl.docx")context = {"col_labels": ["fruit", "vegetable", "stone", "thing"],"tbl_contents": [{"label": "yellow", "cols": ["banana", "capsicum", "pyrite", "taxi"]},{"label": "red", "cols": ["apple", "tomato", "cinnabar", "doubledecker"]},{"label": "green", "cols": ["guava", "cucumber", "aventurine", "card"]},],
}tpl.render(context)
os.makedirs("output",exist_ok=True)
tpl.save("output/dynamic_table.docx")

也可以在for循环中实现单元格水平合并:

{% hm %}

以下代码展示了如何利用hm标签实现单元格水平合并:

# https://github.com/elapouya/python-docx-template/blob/master/tests/horizontal_merge.py
from docxtpl import DocxTemplate
import os
# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/horizontal_merge_tpl.docx
tpl = DocxTemplate("templates/horizontal_merge_tpl.docx")
tpl.render({})
os.makedirs("output",exist_ok=True)
tpl.save("output/horizontal_merge.docx")

此外,还可以在for循环中实现单元格垂直合并:

{% vm %}

以下示例展示了如何实现表格单元格的垂直合并效果:

# https://github.com/elapouya/python-docx-template/blob/master/tests/vertical_merge.py
from docxtpl import DocxTemplate# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/vertical_merge_tpl.docx
tpl = DocxTemplate("templates/vertical_merge_tpl.docx")context = {"items": [{"desc": "Python interpreters", "qty": 2, "price": "FREE"},{"desc": "Django projects", "qty": 5403, "price": "FREE"},{"desc": "Guido", "qty": 1, "price": "100,000,000.00"},],"total_price": "100,000,000.00","category": "Book",
}tpl.render(context)
tpl.save("output/vertical_merge.docx")

若需要修改表格单元格的背景色,必须将以下标签放置在单元格内容的最开头位置:

{% cellbg <var> %}

<var>必须填写颜色的十六进制编码,且无需包含井号(#)。

1.2 复杂元素

1.2.1 富文本

富文本(Rich Text)是相对于纯文本(Plain Text)而言的一种文本格式。它不仅包含文字内容,还支持为文字添加各种格式属性及多媒体元素,从而呈现出更为丰富的视觉效果。这种格式的编辑和处理也可以通过在Microsoft Word软件中预先定义字符样式来实现。

在python-docx-template中使用富文本的步骤如下:

  1. 在Word模板中,为富文本定义一个占位符。例如,使用{{r rich_text_var}},其中的r表示富文本。
  2. 在Python代码中,利用RichText类构建带有格式的文本内容。
  3. 渲染模板时,占位符会被替换为富文本内容,并保留所有已定义的格式样式。

在代码中使用RichText类时,还可通过以下标记控制文本格式:

  • 换行:\n
  • 换段:\a
  • 分页:\f

以下为生成富文本Word文档的示例:

# https://github.com/elapouya/python-docx-template/blob/master/tests/richtext.py
from docxtpl import DocxTemplate, RichText# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/richtext_tpl.docx
tpl = DocxTemplate("templates/richtext_tpl.docx")rt = RichText()# 向富文本对象中添加内容,依次演示不同的文本格式设置
rt.add("a rich text", style="myrichtextstyle")  # 使用自定义样式
rt.add(" with ")                                
rt.add("some italic", italic=True)              # 斜体文本
rt.add(" and ")
rt.add("some violet", color="#ff00ff")          # 紫色文本(十六进制颜色码)
rt.add(" and ")
rt.add("some striked", strike=True)             # 删除线文本
rt.add(" and ")
rt.add("some Highlighted", highlight="#ffff00") # 黄色高亮文本
rt.add(" and ")
rt.add("some small", size=14)                   # 小字号文本(14磅)
rt.add(" or ")
rt.add("big", size=60)                          # 大字号文本(60磅)
rt.add(" text.")
rt.add("\nYou can add an hyperlink, here to ")
# 添加带超链接的文本,build_url_id 用于创建URL标识并关联到指定链接
rt.add("bing", url_id=tpl.build_url_id("http://bing.com"))
rt.add("\nEt voilà ! ")
# 演示换行符效果
rt.add("\n1st line")
rt.add("\n2nd line")
rt.add("\n3rd line")
# \a 用于创建新段落
rt.add("\aA new paragraph : <cool>\a")
# \f 用于插入分页符
rt.add("--- A page break here (see next page) ---\f")# 循环演示不同类型的下划线样式
for ul in ["single",       # 单下划线"double",       # 双下划线"thick",        # 粗下划线"dotted",       # 点下划线"dash",         # 短划线下划线"dotDash",      # 点划线下划线"dotDotDash",   # 双点划线下划线"wave",         # 波浪线下划线
]:rt.add("\nUnderline : " + ul + " \n", underline=ul)# 演示不同字体的设置
rt.add("\nFonts :\n", underline=True)
rt.add("Arial\n", font="Arial")                
rt.add("Courier New\n", font="Courier New")    
rt.add("Times New Roman\n", font="Times New Roman") # 演示上标和下标文本
rt.add("\n\nHere some")
rt.add("superscript", superscript=True)        # 上标文本
rt.add(" and some")
rt.add("subscript", subscript=True)            # 下标文本# 创建一个新的富文本对象,并将之前创建的rt对象嵌入其中,实现富文本嵌套
rt_embedded = RichText("an example of ")
rt_embedded.add(rt)# 构建渲染上下文,将嵌套的富文本对象赋值给模板中的 "example" 变量
context = {"example": rt_embedded,
}# 将上下文数据渲染到Word模板中
tpl.render(context)
# 保存渲染后的Word文档到指定路径
tpl.save("output/richtext.docx")

1.2.2 富文本段落

若要精细控制单个段落的样式,可在代码中使用RichTextParagraph()RP()对象。此对象需通过{{p <var> }}语法添加至模板。示例代码如下:

# https://github.com/elapouya/python-docx-template/blob/master/tests/richtextparagraph.py
from docxtpl import DocxTemplate, RichText, RichTextParagraph# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/richtext_paragraph_tpl.docx
tpl = DocxTemplate("templates/richtext_paragraph_tpl.docx")# 创建富文本段落对象组合不同样式的段落
rtp = RichTextParagraph()
# 创建富文本对象,用于设置文本的字符样式
rt = RichText()# 向富文本段落中添加文本,并指定自定义样式myrichparastyle
rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle",
)
# 添加文本并使用内置段落样式IntenseQuote
rtp.add("Any built in paragraph style can be used", parastyle="IntenseQuote")
# 添加文本并使用自定义样式createdStyle
rtp.add("or you can add your own, unlocking all style options", parastyle="createdStyle"
)
# 添加文本并使用默认普通段落样式normal
rtp.add("To use, just create a style in your template word doc with the formatting you want ""and call it in the code.",parastyle="normal",
)# 演示不同列表样式的使用
rtp.add("This allows for the use of")
rtp.add("custom bullet\apoints", parastyle="SquareBullet")  # 方形项目符号样式
rtp.add("Numbered Bullet Points", parastyle="BasicNumbered")  # 数字编号样式
rtp.add("and Alpha Bullet Points.", parastyle="alphaBracketNumbering")  # 字母编号样式# 演示文本对齐方式的设置
rtp.add("You can", parastyle="normal")  # 默认左对齐
rtp.add("set the", parastyle="centerAlign")  # 应用自定义样式居中对齐
rtp.add("text alignment", parastyle="rightAlign")  # 应用自定义样式右对齐# 演示行间距样式:紧凑行间距
rtp.add("as well as the spacing between lines of text. Like this for example, ""this text has very tight spacing between the lines.\aIt also has no space between ""paragraphs of the same style.",parastyle="TightLineSpacing",
)
# 演示行间距样式:宽行间距
rtp.add("Unlike this one, which has extra large spacing between lines for when you want to ""space things out a bit or just write a little less.",parastyle="WideLineSpacing",
)
# 演示段落背景色样式:绿色背景
rtp.add("You can also set the background colour of a line.", parastyle="LineShadingGreen"
)# 构建富文本字符串,演示字符级样式
rt.add("This works with ")
rt.add("Rich ", bold=True)  # 加粗
rt.add("Text ", italic=True)  # 斜体
rt.add("Strings", underline="single")  # 单下划线
rt.add(" too.")# 将富文本对象添加到富文本段落中,并指定方形项目符号样式
rtp.add(rt, parastyle="SquareBullet")# 构建渲染上下文,将富文本段落对象绑定到模板中的example变量
context = {"example": rtp,
}# 将上下文数据渲染到 Word 模板中
tpl.render(context)
# 保存渲染后的 Word 文档到指定路径
tpl.save("output/richtext_paragraph.docx")

1.2.3 浮动对象

图片插入

可在文档中动态插入单张或多张图片,当前已支持JPEG和PNG格式。只需在模板中使用{{ <var> }}格式的标签即可。图片嵌入代码如下:

myimage = InlineImage(tpl, image_descriptor='test_files/python_logo.png', width=Mm(20), height=Mm(10))

使用时应传入模板对象与图片文件路径,宽高为可选参数。宽度和高度需通过Mm(毫米)、Inches(英寸)或 Pt(磅)等类进行单位定义。示例代码如下:

# https://github.com/elapouya/python-docx-template/blob/master/tests/inline_image.py
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
import jinja2
# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/inline_image_tpl.docx
tpl = DocxTemplate("templates/inline_image_tpl.docx")# 定义渲染模板所需的上下文数据
context = {# 只设置宽或者高,则图片自适应变化"myimage": InlineImage(tpl, "templates/python_logo.png", width=Mm(20)),# 手动指定宽高度"myimageratio": InlineImage(tpl, "templates/python_jpeg.jpg", width=Mm(30), height=Mm(60)),# 定义图片+描述"frameworks": [{"image": InlineImage(tpl, "templates/django.png", height=Mm(10)),"desc": "The web framework for perfectionists with deadlines",},{"image": InlineImage(tpl, "templates/zope.png", height=Mm(10)),"desc": "Zope is a leading Open Source Application Server ""and Content Management Framework",},{"image": InlineImage(tpl, "templates/pyramid.png", height=Mm(10)),"desc": "Pyramid is a lightweight Python web framework aimed at taking ""small web apps into big web apps.",},{"image": InlineImage(tpl, "templates/bottle.png", height=Mm(10)),"desc": "Bottle is a fast, simple and lightweight WSGI micro web-framework ""for Python",},{"image": InlineImage(tpl, "templates/tornado.png", height=Mm(10)),"desc": "Tornado is a Python web framework and asynchronous networking ""library.",},],
}# autoescape是否开启自动转义,把模板变量中的特殊字符转换成无害的HTM实体
jinja_env = jinja2.Environment(autoescape=True)
# 使用上下文数据和自定义的jinja2环境渲染Word模板
tpl.render(context, jinja_env)
tpl.save("output/inline_image.docx")

替换文档中的图片

可对文档中的现有图片进行替换,具体操作如下:先在模板中插入一张占位图,按常规流程渲染模板,之后再将占位图替换为目标图片。该方法支持批量处理文档内的所有媒体文件,且替换后的图片将维持原占位图的纵横比。在模板中插入图片时,只需指定文件名即可。该替换操作同时对页眉、页脚及正文区域生效。

例如,替换占位图dummy_header_pic.jpg的语法示例如下:

tpl.replace_pic('dummy_header_pic.jpg', 'header_pic_i_want.jpg')

注意,在将图片手动插入Word模板时,某些版本的Word会自动对其重命名并存储。这导致图片在docx文件内的实际文件名与原文件名完全不同,从而可能引发找不到图片的问题。若不确定图片的具体位置,可将docx文件视为zip压缩包进行解压,随后在word\document.xml文件中,通过查找pic:nvPicPr节点来定位图片信息。具体步骤可参考:python使用docxtpl库对图片进行替换。

在找到目标图片对应的pic:nvPicPr节点后,其name属性的值即为图片在文档中实际存储的文件名。此处的文件名可能不包含图片格式后缀,替换图片的示例代码可能如下:

tpl.replace_pic('Picture 1','header_pic_i_want.jpg')

1.2.4 子文档

模板变量可包含复杂的子文档对象,且能通过python-docx的文档操作方法从零构建。具体步骤为:先从模板对象中获取子文档对象,再将其当作python-docx文档对象使用。该功能需要安装额外依赖:

pip install "docxtpl[subdoc]"

以下代码展示了如何创建子文档,并将该子文档嵌入到主模板中,最终生成并保存新的文档:

# https://github.com/elapouya/python-docx-template/blob/master/tests/subdoc.py
from docxtpl import DocxTemplate
from docx.shared import Inches# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/subdoc_tpl.docx
# 1. 加载Word模板文件(指定模板文件路径)
tpl = DocxTemplate("templates/subdoc_tpl.docx")# 2. 创建一个新的子文档对象
sd = tpl.new_subdoc()# 3. 向下文档中添加段落内容
p = sd.add_paragraph("This is a sub-document inserted into a bigger one")
p = sd.add_paragraph("It has been ")
# 为文本片段设置自定义样式
p.add_run("dynamically").style = "dynamic"
p.add_run(" generated with python by using ")
# 为文本片段设置斜体样式
p.add_run("python-docx").italic = True
p.add_run(" library")# 4. 向下文档添加标题
sd.add_heading("Heading, level 1", level=1)
# 向下文档添加带样式的段落(IntenseQuote样式为内置样式)
sd.add_paragraph("This is an Intense quote", style="IntenseQuote")# 5. 向下文档插入图片
sd.add_paragraph("A picture :")
sd.add_picture("templates/python_logo.png", width=Inches(1.25))# 6. 向下文档插入表格
sd.add_paragraph("A Table :")
# 创建表格(初始1行3列,作为表头)
table = sd.add_table(rows=1, cols=3)
# 获取表头单元格并设置内容
hdr_cells = table.rows[0].cells
hdr_cells[0].text = "Qty"
hdr_cells[1].text = "Id"
hdr_cells[2].text = "Desc"# 定义表格数据
recordset = ((1, 101, "Spam"), (2, 42, "Eggs"), (3, 631, "Spam,spam, eggs, and ham"))
# 循环添加数据行到表格
for item in recordset:row_cells = table.add_row().cellsrow_cells[0].text = str(item[0])  # 数量(转为字符串)row_cells[1].text = str(item[1])  # ID(转为字符串)row_cells[2].text = item[2]       # 描述context = {"mysubdoc": sd,
}tpl.render(context)
tpl.save("output/subdoc.docx")

此外自python-docx-template V0.12.0版本起,支持将已有的.docx文件作为子文档进行合并,如下所示:

# https://github.com/elapouya/python-docx-template/blob/master/tests/merge_docx.py
from docxtpl import DocxTemplate# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates
tpl = DocxTemplate("templates/merge_docx_master_tpl.docx")
sd = tpl.new_subdoc("templates/merge_docx_subdoc.docx")context = {"mysubdoc": sd,
}tpl.render(context)
tpl.save("output/merge_docx.docx")

1.3 补充操作

1.3.1 转义操作

默认情况下,python-docx-template不会对内容进行转义。这是因为在使用模板语法修改Word文档时,底层实际上是在处理XML结构,而像<>&这样的字符在XML中具有特殊含义,必须经过转义才能正确显示。以下提供几种实现转义的方法:

  1. 上下文定义时使用R()包裹内容,模板中添加r标记:

    context = { 'var': R('my text') }
    

    模板中写法:{{r <var> }}

  2. 上下文保持原始字符串,模板中使用|e过滤器:

    context = { 'var':'my text' }
    

    模板中写法:{{ <var>|e }}

  3. 上下文使用escape()函数处理内容,模板直接引用:

    context = { 'var': escape('my text') }
    

    模板中写法:{{ <var> }}

  4. 调用render方法时启用自动转义,默认值为autoescape=False

    tpl.render(context, autoescape=True)
    

在文档中插入代码清单时,如果需要同时转义文本并处理换行符(\n)、段落符(\a)和换页符(\f),可以在Python代码中使用Listing类。

例如:

context = { 'mylisting': Listing('the listing\nwith\nsome\nlines \a and some paragraph \a and special chars : <>&') 
}

在模板中直接引用即可:

{{ mylisting }}

使用Listing()能够保持当前字符样式,除非遇到\a分隔符,它会在该位置开始一个新的段落。

使用示例如下:

# https://github.com/elapouya/python-docx-template/blob/master/tests/escape.py
from docxtpl import DocxTemplate, R, Listing
# data: https://github.com/elapouya/python-docx-template/blob/master/tests/templates/escape_tpl.docx
tpl = DocxTemplate("templates/escape_tpl.docx")context = {"myvar": R('"less than" must be escaped : <, this can be done with RichText() or R()'),"myescvar": 'It can be escaped with a "|e" jinja filter in the template too : < ',"nlnp": R("Here is a multiple\nlines\nstring\aand some\aother\aparagraphs",color="#ff00ff",),"mylisting": Listing("the listing\nwith\nsome\nlines\nand special chars : <>& ..."),"page_break": R("\f"),"new_listing": """
This is a new listing
Here is a \t tab\a
Here is a page break : \f
That's it
""","some_html": ("HTTP/1.1 200 OK\n""Server: Apache-Coyote/1.1\n""Cache-Control: no-store\n"),
}tpl.render(context)
tpl.save("output/escape.docx")

此外,若需在最终生成的Word文档中显示由Jinja2渲染后的特殊字符%{},可以使用以下方式进行转义:

  • 显示%% → 使用{_% %_}
  • 显示{{ }} → 使用{_{ }_}

1.3.2 获取未定义变量

要获取模板渲染时所需的未定义变量,可以按照以下步骤操作:

from docxtpl import DocxTemplate
tpl = DocxTemplate('template.docx')context = {'name': '张三', 'age': 30}
# 注意:department变量未定义# 检测缺失变量
missing = tpl.get_undeclared_template_variables(context=context)
print(f"缺失的变量: {missing}")# 获取所有变量(不传context)
all_vars = tpl.get_undeclared_template_variables()
print(f"模板所有变量: {all_vars}")

模板文档的内容包含:

姓名:{{name}}
年龄:{{age}}
部门:{{department}}

若未传递 context 参数,该方法将返回模板中所有需要赋值的变量名的集合。此结果可用于向用户提示输入,或写入文件供后续手动处理。

1.3.3 Jinja自定义过滤器

Python-docx-template的render方法支持一个可选参数jinja_env,作为其第二个参数。通过传递自定义的Jinja环境对象,可以实现自定义过滤器的添加,从而灵活扩展数据处理逻辑。以下为具体示例。

模板word内容如下:

=== 姓名展示对比 ===
原始名字: {{ name }}
方法A (Python处理): {{ name_upper }}
方法B (模板过滤器): {{ name|upper }}

对应的Python渲染代码:

from docxtpl import DocxTemplate
import jinja2# 准备数据
data = {'name': 'zhangsan'}# Python中处理
data['name_upper'] = data['name'].upper()# 定义过滤器
def my_upper(text):return text.upper()doc = DocxTemplate("template.docx")#创建环境并注册过滤器
env = jinja2.Environment()
env.filters['upper'] = my_upper doc.render(data, env) 
doc.save("output/compare.docx")
print(f"原始数据: {data['name']}")
print(f"Python处理结果: {data['name_upper']}")
print(f"模板过滤器结果: {data['name'].upper()}")

1.3.4 Microsoft Word 2016特殊行为说明

MS Word 2016会忽略文档中的制表符,这是该版本特有的情况。类似LibreOffice或WordPad等其他编辑工具则无此问题。同样,以Jinja2标签开头且带有前导空格的行,其空格也会被忽略。

为解决上述问题,可使用RichText进行处理:

tpl.render({'test_space_r': RichText('          '),'test_tabs_r': RichText(5 * '\t'),
})

在模板中,通过{{r ... }}语法调用:

{{r test_space_r}} 空格将被保留
{{r test_tabs_r}} 制表符将正常显示

2 参考

  • 基于python-docx库的Word文档自动处理全解
  • python-docx-template
  • python-docx-template doc
  • python使用docxtpl库对图片进行替换

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询