Add header and footer support
This commit is contained in:
parent
f599a5d3ee
commit
41baec8d2e
16
CHANGES.rst
16
CHANGES.rst
@ -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)
|
||||
|
||||
@ -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
|
||||
------------------
|
||||
|
||||
|
||||
@ -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"‘","'").replace('<','<').replace('>','>')
|
||||
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
19
tests/header_footer.py
Normal 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
12
tests/runtests.py
Normal 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.'
|
||||
@ -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.
BIN
tests/test_files/header_footer.docx
Normal file
BIN
tests/test_files/header_footer.docx
Normal file
Binary file not shown.
BIN
tests/test_files/header_footer_tpl.docx
Normal file
BIN
tests/test_files/header_footer_tpl.docx
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user