docxtpl使用手册
作者:小小明
本文鏈接:https://blog.csdn.net/as604049322/article/details/112008531
支持pdf文檔下載:https://download.csdn.net/download/as604049322/13993564
簡介: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/
安裝:
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")docxtpl的使用手冊
Jinja2語法
為了掌握docxtpl 的用法,我們需要學習或復習一下Jinja2的語法,然后再研究docxtpl 特有的類Jinja2語法。
基本語法:
{% if user %}<title> hello {{user}} </title> {% else %}<title> welcome to docxtpl </title> {% endif %} <ul>{% for index in indexs %}<li> {{ index }} </li>{% endfor %} </ul>在模板中{{ variable }}結構表示變量,是一種特殊的占位符,告訴模板引擎這個位置的值,從渲染模板時使用的數據中獲取;Jinja2除了能識別基本類型的變量,還能識別字典;
<p>{{mydict['key']}}</p><p>{{mylist[1]}}</p><p>{{mylist[myvariable]}}</p>過濾器的本質就是函數,使用方式為:變量名 | 過濾器。 過濾器名寫在變量名后面,中間用 | 分隔。如:{{variable | capitalize}},這個過濾器的作用:把變量variable的值的首字母轉換為大寫,其他字母轉換為小寫。 操作列表的常用過濾器如下:
列表操作:
first:取第一個元素
<p>{{ [1,2,3,4,5,6] | first }}</p>last:取最后一個元素
<p>{{ [1,2,3,4,5,6] | last }}</p>length:獲取列表長度
<p>{{ [1,2,3,4,5,6] | length }}</p>sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p>sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>Jinja自定義過濾器
render() 的 jinja_env 選項參數可以傳遞一個jinja環境對象,從而添加一些定制的jinja過濾器:
from docxtpl import DocxTemplate import jinja2 def multiply_by(value, by):return value * bytpl = 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")然后在模板中能夠使用
Euros price : {{ price_dollars|multiply_by(0.88) }}類Jinja 2語法
4個重要的專屬標簽
為了管理段落、表行、表列、run,必須使用特殊的語法:
{%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源代碼中的正確位置。
另外,需注意,這四種標簽,起始標簽不能在同一行,必須在不同的行上面。
例如:
{%p if display_paragraph %}Here is my paragraph {%p endif %}需改寫成:
{%p if display_paragraph %} Here is my paragraph {%p endif %}否則無法正確渲染。
長文本拆分
包含jinja2標簽的文本如果太長,可能無法讀取:
My house is located {% if living_in_town %} in urban area {% else %} in countryside {% endif %} and I love it.可以使用 {%- 和-%} 標簽來拆分整個文本:
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 }}
注意:
表格處理與合并單元格
列跨越:
如果需要動態生成一個合并單元格,可以使用colspan標記:
{% colspan column_count %}column_count是一個整數表示要跨越的列數。
例如,word模板中:
| {%tc for col in col_labels %} | {{ col }} | {%tc endfor %} |
python渲染代碼:
tpl.render({'col_labels': ['fruit', 'vegetable', 'stone', 'thing']})渲染結果:
水平合并單元格:
或者在for循環中:
{% hm %}例如,word模板:
| {%tc for x in [1, 2, 3, 4] %} | Subheader {{ x }} | {%tc endfor %} |
最終渲染結果:
垂直合并單元格:
在for循環中:
{% vm %}例如,word模板:
| {%tr for i in items %} | |||
| {% vm %}{{category}} | {{ i.desc }} | {{ i.qty }} | {{ i.price }} |
| {%tr endfor %} | |||
| Total | {{total_price}} |
python渲染代碼:
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將超鏈接添加到文本中:
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代碼示例:
from docxtpl import DocxTemplate, RichTexttpl = 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文件模板內容:
{%r if foobar %} {{r foobar }}COUCOU{%r endif %}渲染結果:
單元格顏色
需要更改表格單元格的背景色時,必須在單元格的開頭放置以下標記
{% cellbg variable %}variable 必須是顏色的十六進制碼,不支持red等顏色單詞。
比如模板:
| {%tr for a in alerts %} | ||
| {{ a.date }} | {% cellbg a.bg %}{{ a.type }} | {{r a.desc }} |
| {%tr endfor %} |
python渲染代碼:
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',},{'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 }}, 可以使用:
{_%, %_}, {_{ or }_}傳入 {{ variable }}的variable 變量不能使用<, > 和&等字符,必須轉義它們,否則會導致整個文檔錯亂。
轉義方法有 :
- context = { 'variable':R('my text') } 和在模板中{{r variable }}
- context = { 'variable':'my text'}和在模板中{{ variable|e }}
- context = { 'var':escape('my text')} 和在模板中{{ <var> }}
- 在調用渲染方法時啟用自動轉義:tpl.render(context, autoescape=True) (默認值autoescape=False)
RichText()或R()支持換行符,新段落,縮進和分頁符功能:只需使用\n, \a, \t 或\f 在文本中,它們將作相應的轉換。
示例:
word模板內容:
{{orgin}}{{r var1}}{{var2|e}}{{var3}}{{ var4}}python渲染腳本:
context = {'var1': R('<>&:必須被轉義才能顯示, 可以使用RichText() 或 R()'),'var2': '或者使用 "|e" jinja 過濾器來轉義 <>& ','var3': escape('或者使用escape函數來轉義: <>& ...'),'var4': '多行文本\n\ttab縮進和一些段落\n會自動\a被轉換', }tpl.render(context)渲染結果:
假如不轉義,直接傳入這些特殊字符:
context = {'orgin': '直接傳入<>&看看渲染結果:','var1': R('<>&:必須被轉義才能顯示, 可以使用RichText() 或 R()'),'var2': '或者使用 "|e" jinja 過濾器來轉義 <>& ','var3': escape('或者使用escape函數來轉義: <>& ...'),'var4': '多行文本\n\ttab縮進和一些段落\n會自動\a被轉換', }tpl.render(context)渲染結果:
結果就是會導致其他已經轉義的<>&等字符都無法正常顯示。
如果希望可以直接安全的轉入這些字符,可以開啟自動轉義:
context = {'orgin': '<>&沒有轉義的情況下無法顯示','var1': R('<>&:必須被轉義才能顯示, 可以使用RichText() 或 R()'),'var2': '或者使用 "|e" jinja 過濾器來轉義 <>& ','var3': escape('或者使用escape函數來轉義: <>& ...'),'var4': '多行文本\n\ttab縮進和一些段落\n會自動\a被轉換', }tpl.render(context, autoescape=True)渲染結果:
docxtpl的2個高級對象
內嵌圖像
doxtpl.inlineImage對象可以動態地將一個或多個圖像添加到文檔中(支持JPEG和PNG格式)。
from docx.shared import Mmmyimage=InlineImage(tpl,'python_logo.png',width=Mm(20))對于高度和寬度,必須使用毫米(毫米),英寸(英寸)或點(Pt)類。
示例
word模板:
python渲染代碼:
from docxtpl import DocxTemplate, InlineImage# for height and width you have to use millimeters (Mm), inches or points(Pt) class : from docx.shared import Mm import jinja2tpl = 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.',},], } # testing that it works also when autoescape has been forced to True jinja_env = jinja2.Environment(autoescape=True) tpl.render(context, jinja_env) tpl.save('output/inline_image.docx')渲染結果:
子文件
Subdoc對象可以作為一個使用python-docx庫從頭開始構建word文檔的對象,構建的內容可以直接嵌入到傳入的變量位置:
sd = tpl.new_subdoc() 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')context = {'mysubdoc': sd, } tpl.render(context)效果:
替換word文檔的圖片或媒體
在頁眉/頁腳中是無法動態添加圖片和媒體的,但我們可以在模板中放置一個虛擬對象,像往常一樣渲染模板,然后用另一個對象替換虛擬對象。從而實現圖片和媒體的添加。
替換可以發生在頁眉、頁腳和整個文檔正文中。
替換頁眉/頁腳中的圖片
需要先在頁眉/頁腳中放置一張模板圖片,替換時指定被插入的模板圖片的文件名即可,替換dummy_header_pic.jpg的語法:
tpl.replace_pic('dummy_header_pic.jpg','header_pic_i_want.jpg')被替換的圖像在word文檔中將保持原始文檔的寬高比。
替換頁眉/頁腳中的媒體
與替換圖片幾乎一致,替換dummy_header_pic.jpg的語法:
tpl.replace_media('dummy_header_pic.jpg','header_pic_i_want.jpg')警告:與replace_pic() 方法不同,dummy_header_pic.jpg 必須存在模板目錄中。
替換嵌入對象
它的工作方式類似于媒體替換,只是它適用于嵌入式docx這樣的嵌入式對象。
替換embedded_dummy.docx的語法:
tpl.replace_embedded('embdded_dummy.docx','embdded_docx_i_want.docx')警告:與replace_pic()方法不同,embdded_dumy.docx必須存在于模板目錄中。
總結
以上是生活随笔為你收集整理的docxtpl使用手册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OOP_多态(C#)
- 下一篇: 静电场