作者:小小明
本文链接:https://blog.csdn.net/as604049322/article/details/112008531
简介:Pandas数据处理专家,10余年编码经验。
若你在数据处理的问题上遇到什么困难,欢迎与我交流。
大家好,我是小小明,这篇文章将给大家分享一个强大的包docxtpl ,它通过对docx文档模板加载,使
用jinja2网页模板开发的语法对其进行修改。
docxtpl 的简介
前面我分享过python-docx库的操作案例,而这次分享的docxtpl 就是基于python-docx和jinja2开发出
来的库。
docxtpl 的作者开发出它的原因主要是python-docx擅长创建word文档,却不擅长修改。
对于docxtpl来说,使用MicrosoftWord编辑文档时,直接在文档中插入类似于Jinja2的标记。将文档保
存为.docx文件(XML格式):它将是.docx模板文件。
然后使用docxtpl加载这个.docx模板,按照Jinja2的语法传入关联的上下文变量,即可生成想要的Word
文档,多次传入不同的上下文变量即可生成多个基于模板的word文档。
docxtpl 主要依赖两个包
python-docx :读写word文档
jinja2:管理插入到模板中的标签
jinja2语法可参考: http://docs.jinkan.org/docs/jinja2/templates.html docxtpl官方文档:
https://docxtpl.readthedocs.io/en/latest/
安装:
1
pip install docxtpl
基本使用示例:
from docxtpl import DocxTemplate
tpl = DocxTemplate("my_word_template.docx")
context = { 'company_name' : "World company" }
tpl.render(context)
tpl.save("generated_doc.docx")
1
2
3
4
5
docxtpl的使用手册
Jinja2语法
为了掌握docxtpl 的用法,我们需要学习或复习一下Jinja2的语法,然后再研究docxtpl 特有的类Jinja2
语法。
基本语法:
1
2
3
4
5
6
7
8
9
{% if user %}
hello {{user}}
{% else %}
welcome to docxtpl
{% endif %}
{% for index in indexs %}
- {{ index }}
{% endfor %}
10
在模板中{{ variable }}结构表示变量,是一种特殊的占位符,告诉模板引擎这个位置的值,从渲染模板
时使用的数据中获取;Jinja2除了能识别基本类型的变量,还能识别字典;
1
2
3
4
5
{{mydict['key']}}
{{mylist[1]}}
{{mylist[myvariable]}}
过滤器的本质就是函数,使用方式为:变量名 | 过滤器。 过滤器名写在变量名后面,中间用 | 分隔。
如:{{variable | capitalize}},这个过滤器的作用:把变量variable的值的首字母转换为大写,其他字
母转换为小写。 操作列表的常用过滤器如下:
列表操作:
first:取第一个元素
1
{{ [1,2,3,4,5,6] | first }}
last:取最后一个元素
1
{{ [1,2,3,4,5,6] | last }}
length:获取列表长度
1
{{ [1,2,3,4,5,6] | length }}
sum:列表求和
1
{{ [1,2,3,4,5,6] | sum }}
sort:列表排序
1
{{ [6,2,3,1,5,4] | sort }}
Jinja自定义过滤器
render() 的 jinja_env 选项参数可以传递一个jinja环境对象,从而添加一些定制的jinja过滤器:
1
2
3
4
5
6
7
8
9
10
11
from docxtpl import DocxTemplate
import jinja2
def multiply_by(value, by):
return value * by
tpl = DocxTemplate("my_word_template.docx")
context = { 'price_dollars' : 5.00 }
jinja_env = jinja2.Environment()
jinja_env.filters['multiply_by'] = multiply_by
tpl.render(context,jinja_env)
tpl.save("generated_doc.docx")
然后在模板中能够使用
1
Euros price : {{ price_dollars|multiply_by(0.88) }}
类Jinja 2语法
4个重要的专属标签
为了管理段落、表行、表列、run,必须使用特殊的语法:
1
2
3
4
{%p jinja2_tag %} for paragraphs
{%tr jinja2_tag %} for table rows
{%tc jinja2_tag %} for table columns
{%r jinja2_tag %} for runs
正常的Jinja 2语法只有%的普通标签,而docxtpl的类语法包含%p,%tr,%tc,%r
%p:段落,即docx.text.paragraph.Paragraph对象
%tr:表格中的一行,即docx.table._Row对象
%tc:表格中的一列,即docx.table._Column对象
%r:段落中的一个片段,即docx.text.run.Run对象
通过使用这些标记,python-docx-template将真正的Jinja 2标记放入文档的XML源代码中的正确位置。
另外,需注意,这四种标签,起始标签不能在同一行,必须在不同的行上面。
例如:
1
{%p if display_paragraph %}Here is my paragraph {%p endif %}
需改写成:
1
2
3
{%p if display_paragraph %}
Here is my paragraph
{%p endif %}
否则无法正确渲染。
长文本拆分
包含jinja2标签的文本如果太长,可能无法读取:
1
My house is located {% if living_in_town %} in urban area {% else %} in
countryside {% endif %} and I love it.
可以使用 {%- 和 -%} 标签来拆分整个文本:
1
2
3
4
5
6
7
My house is located
{%- if living_in_town -%}
in urban area
{%- else -%}
in countryside
{%- endif -%}
and I love it.
注意: {%- xxx -%} 标签必须在单独在一行中,不可在之前或之后添加其他的文本。
Jinja 2的语法对变量是使用双括弧:{{ variable }}
但如果variable 是RichText对象时,必须更改为:{{r variable }}
注意:
1. r紧跟左括弧。variable不能使用r作为变量,因为{{r}} 可以解释为 {{r 没有指定变量
2. 不要在同一run上使用2次 {{r . 使用 RichText.add() 方法在python代码上连接多个字符串
和样式,在word文档模板上只需 写一个 {{r 标签。
表格处理与合并单元格
列跨越:
如果需要动态生成一个合并单元格,可以使用colspan标记:
1
{% colspan column_count %}
column_count是一个整数表示要跨越的列数。
例如,word模板中:
{% colspan col_labels|count %}Type of thing
{%tc for col in col_labels %}
{{ col }}
{%tc endfor %}
python渲染代码:
1
tpl.render({'col_labels': ['fruit', 'vegetable', 'stone', 'thing']})
渲染结果:
水平合并单元格:
或者在for循环中:
1
{% hm %}
例如,word模板:
{%tc for x in [1, 2, 3, 4] %}
{% hm %}Header 2
{%tc endfor %}
{%tc for x in [1, 2, 3, 4] %}
Subheader {{ x }}
{%tc endfor %}
最终渲染结果:
垂直合并单元格:
在for循环中:
1
{% vm %}
例如,word模板:
Description
Quantity
{%tr for i in items %}
Price
{% vm %}{{category}}
{{ i.desc }}
{{ i.qty }}
{{ i.price }}
{%tr endfor %}
Total
python渲染代码:
{{total_price}}
1
2
3
4
5
6
7
8
9
10
11
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)
渲染结果:
RichText动态样式
使用{{ variable }}标记,它将保持目前的格式使用variable 变量的值进行字符串替换。但如果要添加动
态变化的样式,则必须使用{{r variable }}标记,同时传入的variable变量是一个 RichText对象。
RichText对象可以在python代码中更改颜色、粗体、斜体、大小等。
使用{{r variable }}标记时,它在docx模板中原本的样式将会被删除,如果没有在RichText()设置字体样
式,样式将返回到Microsoft Word默认样式。
还可以通过Richtext将超链接添加到文本中:
1
2
3
tpl=DocxTemplate('your_template.docx')
rt = RichText('You can add an hyperlink, here to ')
rt.add('google',url_id=tpl.build_url_id('http://google.com'))
RichText('my text')的简写是R('my text')
python代码示例:
1
2
3
4
5
6
7
from docxtpl import DocxTemplate, RichText
tpl = DocxTemplate('templates/richtext_and_if_tpl.docx')
context = {'foobar': RichText('Foobar!', color='ff0000')}
tpl.render(context)
tpl.save('output/richtext_and_if.docx')
richtext_and_if_tpl.docx文件模板内容:
1
{%r if foobar %} {{r foobar }}COUCOU{%r endif %}
渲染结果:
单元格颜色
需要更改表格单元格的背景色时,必须在单元格的开头放置以下标记
1
{% cellbg variable %}
variable 必须是颜色的十六进制码,不支持red等颜色单词。
比如模板:
Date
{%tr for a in alerts %}
Type
Alert Description
{{ a.date }}
{% cellbg a.bg %}{{ a.type }}
{{r a.desc }}
{%tr endfor %}
python渲染代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
context = {
'alerts': [
{
'date': '2015-03-10',
'desc': RichText('Very critical alert', color='FF0000',
bold=True),
'type': 'CRITICAL',
'bg': 'FF0000',
},
{
'date': '2015-03-11',
'desc': RichText('Just a warning'),
'type': 'WARNING',
'bg': 'FFDD00',
},
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
'date': '2015-03-12',
'desc': RichText('Information'),
'type': 'INFO',
'bg': '8888FF',
},
{
'date': '2015-03-13',
'desc': RichText('Debug trace'),
'type': 'DEBUG',
'bg': 'FF00FF',
},
],
}
tpl.render(context)
渲染结果:
Escaping和转义
为了展示 {% , %} , {{ or }} , 可以使用:
1
{_%, %_}, {_{ or }_}
传入 {{ variable }} 的variable 变量不能使用 < , > 和 & 等字符,必须转义它们,否则会导致整个文
档错乱。
转义方法有 :
context = { 'variable':R('my text') } 和在模板中 {{r variable }}
context = { 'variable':'my text'} 和在模板中 {{ variable|e }}
context = { 'var':escape('my text')} 和在模板中 {{ }}
在调用渲染方法时启用自动转义: tpl.render(context, autoescape=True) (默认值
autoescape=False)
RichText()或R()支持换行符,新段落,缩进和分页符功能:只需使用 \n , \a , \t 或 \f 在文本中,它
们将作相应的转换。
示例: