python-docx-template icon indicating copy to clipboard operation
python-docx-template copied to clipboard

Accepting docx as file-like object, and saving to file-like object

Open bgswe opened this issue 3 years ago • 4 comments

python-docx accepts a file path to a docx file, or a file-like object in it's constructor. It also allows saving to a file-like object.

As far as I can tell, python-docx-template only accepts the file path.

I have a requirement to do template a docx in memory. Is the file-like object supported?

bgswe avatar Feb 12 '22 20:02 bgswe

Hi @bgswe , Did you tried to put a file-like object into the constructor of DocxTemplate ?

I see here that the module passes the argument directly to the docx module which supports file-like and file path. https://github.com/elapouya/python-docx-template/blob/23038b98de1f5d8cc710145ceda596a61816583a/docxtpl/template.py#L46

I also see that the save() method calls save from docx which supports streams. https://github.com/elapouya/python-docx-template/blob/23038b98de1f5d8cc710145ceda596a61816583a/docxtpl/template.py#L713

fldardenne avatar Feb 20 '22 16:02 fldardenne

@fdardenne Hey! Thanks for getting back to me!

While I'd like to say that I did, and it failed, you certainly have me second-guessing myself. I will test and get back to you!

bgswe avatar Feb 25 '22 19:02 bgswe

I confirm it works with rb and wb open modes.

karolzlot avatar Jun 04 '22 04:06 karolzlot

Indeed it works, see the following simple code example. Also, handling subdocuments like their own template and saving them to memory before including them as subdocument seems to be the only way to render subdocuments and therefore the only way to include subdocuments recursively. Or am I missing a simpler way to achieve that? Maybe it's a nice example to include in the tests folder.

from io import BytesIO
from docxtpl import DocxTemplate

# test2.docx template is a word document with just {{ var1 }} and {{p subdoc }}

template_as_subdoc = DocxTemplate('test2.docx')
template_as_subdoc.render({"var1": "template_as_subdoc", "subdoc": None })

document = BytesIO()
template_as_subdoc.save(document)  # save to memory
document.seek(0)


template_as_maindoc = DocxTemplate('test2.docx')
subdoc = template_as_maindoc.new_subdoc(document)  # read from memory
template_as_maindoc.render({"var1": "template_as_maindoc", "subdoc": subdoc })

template_as_maindoc.save('maindoc.docx')

RemcoTukker avatar Jun 11 '22 10:06 RemcoTukker