fix #392
This commit is contained in:
parent
d22aeb41db
commit
589262664f
17
CHANGES.rst
17
CHANGES.rst
@ -1,3 +1,8 @@
|
||||
0.15.0 (2021-12-20)
|
||||
-------------------
|
||||
- Multi-rendering with same DocxTemplate object is now possible
|
||||
see tests/multi_rendering.py
|
||||
|
||||
0.14.1 (2021-10-01)
|
||||
-------------------
|
||||
- One can now use python -m docxtpl on command line
|
||||
@ -22,21 +27,9 @@
|
||||
0.11.5 (2021-05-09)
|
||||
-------------------
|
||||
- PR #351
|
||||
|
||||
0.11.4 (2021-04-06)
|
||||
-------------------
|
||||
- It is now possible to put InlineImage in header/footer
|
||||
|
||||
0.11.2 (2020-11-09)
|
||||
-------------------
|
||||
- fix #323
|
||||
|
||||
0.11.1 (2020-10-27)
|
||||
-------------------
|
||||
- fix #320
|
||||
|
||||
0.11.0 (2020-10-19)
|
||||
-------------------
|
||||
- \\n, \\a, \\t and \\f are now accepted in simple context string. Thanks to chabErch@github
|
||||
|
||||
0.10.5 (2020-10-15)
|
||||
|
||||
@ -4,7 +4,7 @@ Created : 2015-03-12
|
||||
|
||||
@author: Eric Lapouyade
|
||||
"""
|
||||
__version__ = '0.14.2'
|
||||
__version__ = '0.15.0'
|
||||
|
||||
# flake8: noqa
|
||||
from .inline_image import InlineImage
|
||||
|
||||
@ -34,15 +34,24 @@ class DocxTemplate(object):
|
||||
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)
|
||||
self.crc_to_new_media = {}
|
||||
self.crc_to_new_embedded = {}
|
||||
self.zipname_to_replace = {}
|
||||
self.pics_to_replace = {}
|
||||
def __init__(self, template_file):
|
||||
self.template_file = template_file
|
||||
self.reset_replacements()
|
||||
self.docx = None
|
||||
self.is_rendered = False
|
||||
self.is_saved = False
|
||||
|
||||
def init_docx(self):
|
||||
if not self.docx or self.is_rendered:
|
||||
self.docx = Document(self.template_file)
|
||||
self.is_rendered = False
|
||||
|
||||
def render_init(self):
|
||||
self.init_docx()
|
||||
self.pic_map = {}
|
||||
self.current_rendering_part = None
|
||||
self.docx_ids_index = 1000
|
||||
self.is_saved = False
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.docx, name)
|
||||
@ -53,6 +62,7 @@ class DocxTemplate(object):
|
||||
return etree.tostring(xml, encoding='unicode', pretty_print=False)
|
||||
|
||||
def get_docx(self):
|
||||
self.init_docx()
|
||||
return self.docx
|
||||
|
||||
def get_xml(self):
|
||||
@ -307,6 +317,9 @@ class DocxTemplate(object):
|
||||
self.docx._part._rels[relKey]._target = new_part
|
||||
|
||||
def render(self, context, jinja_env=None, autoescape=False):
|
||||
# init template working attributes
|
||||
self.render_init()
|
||||
|
||||
if autoescape:
|
||||
if not jinja_env:
|
||||
jinja_env = Environment(autoescape=autoescape)
|
||||
@ -337,6 +350,9 @@ class DocxTemplate(object):
|
||||
for relKey, xml in footers:
|
||||
self.map_headers_footers_xml(relKey, xml)
|
||||
|
||||
# set rendered flag
|
||||
self.is_rendered = True
|
||||
|
||||
# using of TC tag in for cycle can cause that count of columns does not
|
||||
# correspond to real count of columns in row. This function is able to fix it.
|
||||
def fix_tables(self, xml):
|
||||
@ -432,6 +448,7 @@ class DocxTemplate(object):
|
||||
elt.attrib['id'] = str(self.docx_ids_index)
|
||||
|
||||
def new_subdoc(self, docpath=None):
|
||||
self.init_docx()
|
||||
return Subdoc(self, docpath)
|
||||
|
||||
@staticmethod
|
||||
@ -540,6 +557,27 @@ class DocxTemplate(object):
|
||||
with open(dst_file, 'rb') as fh:
|
||||
self.zipname_to_replace[zipname] = fh.read()
|
||||
|
||||
def reset_replacements(self):
|
||||
"""Reset replacement dictionnaries
|
||||
|
||||
This will reset data for image/embedded/zipname replacement
|
||||
|
||||
This is useful when calling several times render() with different
|
||||
image/embedded/zipname replacements without re-instantiating
|
||||
DocxTemplate object.
|
||||
In this case, the right sequence for each rendering will be :
|
||||
- reset_replacements(...)
|
||||
- replace_zipname(...), replace_media(...) and/or replace_embedded(...),
|
||||
- render(...)
|
||||
|
||||
If you instantiate DocxTemplate object before each render(),
|
||||
this method is useless.
|
||||
"""
|
||||
self.crc_to_new_media = {}
|
||||
self.crc_to_new_embedded = {}
|
||||
self.zipname_to_replace = {}
|
||||
self.pics_to_replace = {}
|
||||
|
||||
def post_processing(self, docx_file):
|
||||
if (self.crc_to_new_media or
|
||||
self.crc_to_new_embedded or
|
||||
@ -662,13 +700,19 @@ class DocxTemplate(object):
|
||||
self.pic_map.update(part_map)
|
||||
|
||||
def build_url_id(self, url):
|
||||
self.init_docx()
|
||||
return self.docx._part.relate_to(url, REL_TYPE.HYPERLINK,
|
||||
is_external=True)
|
||||
|
||||
def save(self, filename, *args, **kwargs):
|
||||
# case where save() is called without doing rendering
|
||||
# ( user wants only to replace image/embedded/zipname )
|
||||
if not self.is_saved and not self.is_rendered:
|
||||
self.docx = Document(self.template_file)
|
||||
self.pre_processing()
|
||||
self.docx.save(filename, *args, **kwargs)
|
||||
self.post_processing(filename)
|
||||
self.is_saved = True
|
||||
|
||||
def get_undeclared_template_variables(self, jinja_env=None):
|
||||
xml = self.get_xml()
|
||||
|
||||
40
tests/multi_rendering.py
Normal file
40
tests/multi_rendering.py
Normal file
@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Created : 2021-12-20
|
||||
|
||||
@author: Eric Lapouyade
|
||||
'''
|
||||
|
||||
from docxtpl import DocxTemplate
|
||||
|
||||
tpl = DocxTemplate('templates/multi_rendering_tpl.docx')
|
||||
|
||||
documents_data = [
|
||||
{
|
||||
'dest_file': 'multi_render1.docx',
|
||||
'context': {
|
||||
'title': 'Title ONE',
|
||||
'body': 'This is the body for first document'
|
||||
}
|
||||
},
|
||||
{
|
||||
'dest_file': 'multi_render2.docx',
|
||||
'context': {
|
||||
'title': 'Title TWO',
|
||||
'body': 'This is the body for second document'
|
||||
}
|
||||
},
|
||||
{
|
||||
'dest_file': 'multi_render3.docx',
|
||||
'context': {
|
||||
'title': 'Title THREE',
|
||||
'body': 'This is the body for third document'
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
for document_data in documents_data:
|
||||
dest_file = document_data['dest_file']
|
||||
context = document_data['context']
|
||||
tpl.render(context)
|
||||
tpl.save(f'output/{dest_file}')
|
||||
BIN
tests/templates/multi_rendering_tpl.docx
Normal file
BIN
tests/templates/multi_rendering_tpl.docx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user