Add header and footer support

This commit is contained in:
Eric Lapouyade 2016-03-17 09:38:50 +01:00
parent f599a5d3ee
commit 41baec8d2e
13 changed files with 72 additions and 15 deletions

View File

@ -1,14 +1,18 @@
0.1.11 (2016-3-1)
-----------------
0.2.0 (2016-03-17)
------------------
- Add Header and Footer support (Thanks to Debby Weinberg)
0.1.11 (2016-03-1)
------------------
- '>' and '<' can now be used inside jinja tags
0.1.10 (2016-2-11)
------------------
0.1.10 (2016-02-11)
-------------------
- render() accepts optionnal jinja_env argument :
useful to set custom filters and other things
0.1.9 (2016-1-18)
-----------------
0.1.9 (2016-01-18)
------------------
- better subdoc management : accept tables
0.1.8 (2015-11-05)

View File

@ -40,11 +40,6 @@ Now you can use python-docx-template to generate as many word documents you want
Note : python-docx-template as been tested with MS Word 97, it may not work with other version.
Note 2 : As python-docx does not manage headers and footers, this is the same for python-docx-template.
Nevertheless, it is possible to manage them though Microsoft word : the idea is to create a variable
inside word document and then use it (or link it) in the header, the footer and the body. When the template modify a variable
in the body, MS Word will update headers and footers automatically.
Jinja2-like syntax
------------------

View File

@ -5,7 +5,7 @@ Created : 2015-03-12
@author: Eric Lapouyade
'''
__version__ = '0.1.11'
__version__ = '0.2.0'
from lxml import etree
from docx import Document
@ -16,6 +16,10 @@ import six
class DocxTemplate(object):
""" Class for managing docx files as they were jinja2 templates """
HEADER_URI = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header"
FOOTER_URI = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"
def __init__(self, docx):
self.docx = Document(docx)
@ -57,7 +61,7 @@ class DocxTemplate(object):
def clean_tags(m):
return m.group(0).replace(r"&#8216;","'").replace('&lt;','<').replace('&gt;','>')
src_xml = re.sub(r'(?<=\{[\{%])([^\}%]*)(?=[\}%]})',clean_tags,src_xml)
src_xml = re.sub(r'(?<=\{[\{%])([^\}%]*)(?=[\}%]})',clean_tags,src_xml)
return src_xml
@ -81,10 +85,33 @@ class DocxTemplate(object):
body = root.body
root.replace(body,etree.fromstring(xml))
def get_headers_footers_xml(self, uri):
for relKey, val in self.docx._part._rels.items():
if val.reltype == uri:
yield relKey, val._target._blob.decode()
def build_headers_footers_xml(self,context, uri,jinja_env=None):
for relKey, xml in self.get_headers_footers_xml(uri):
xml = self.patch_xml(xml)
xml = self.render_xml(xml, context, jinja_env)
yield relKey, xml
def map_headers_footers_xml(self, relKey, xml):
self.docx._part._rels[relKey]._target._blob = xml.encode()
def render(self,context,jinja_env=None):
# Body
xml = self.build_xml(context,jinja_env)
self.map_xml(xml)
# Headers
for relKey, xml in self.build_headers_footers_xml(context, self.HEADER_URI, jinja_env):
self.map_headers_footers_xml(relKey, xml)
# Footers
for relKey, xml in self.build_headers_footers_xml(context, self.FOOTER_URI, jinja_env):
self.map_headers_footers_xml(relKey, xml)
def new_subdoc(self):
return Subdoc(self)

19
tests/header_footer.py Normal file
View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
'''
Created : 2015-03-12
@author: Eric Lapouyade
'''
from docxtpl import DocxTemplate
tpl=DocxTemplate('test_files/header_footer_tpl.docx')
context = {
'title' : 'Header and footer test',
'company_name' : 'The World Wide company',
'date' : '2016-03-17'
}
tpl.render(context)
tpl.save('test_files/header_footer.docx')

12
tests/runtests.py Normal file
View File

@ -0,0 +1,12 @@
import subprocess
import glob
tests = glob.glob('[A-Za-z]*.py')
excludes = ['runtests.py']
for test in tests:
if test not in excludes:
print '%s ...' % test
subprocess.call(['python','./%s' % test])
print 'Done.'

View File

@ -22,7 +22,7 @@ sd.add_heading('Heading, level 1', level=1)
sd.add_paragraph('This is an Intense quote', style='IntenseQuote')
sd.add_paragraph('A picture :')
sd.add_picture('python_logo.png', width=Inches(1.25))
sd.add_picture('test_files/python_logo.png', width=Inches(1.25))
sd.add_paragraph('A Table :')
table = sd.add_table(rows=1, cols=3)
@ -39,7 +39,7 @@ for item in recordset:
row_cells[1].text = str(item[1])
row_cells[2].text = item[2]
context = {
context = {
'mysubdoc' : sd,
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Binary file not shown.