python-docx-template
python-docx-template copied to clipboard
Table width becomes narrower after render
The DocxTemplate#fix_tables
does not fix width of a table.
Details
The problem is that DocxTemplate#fix_tables
correctly updates <w:tblGrid>
but does not change <w:tcW>
of an individual cell. MS Word prioritizes <w:tcW>
over <w:tblGrid>
(see this link) and renders cells with same widths.
How to reproduce
Render the template such as the one below and open the output file in MS Word.
Expected behavior
Total width of a table does not change after template rendering and cells become wider. The result should look somewhat like this:
Actual behavior
Actual widths of cells stay the same and, therefore, total width of a table reduces after rendering. The result looks like this:
Possible solution
Currently, my quick-and-dirty workaround is to remove individual width of a cell (<w:tcW>
) for the entire document:
for tc_w in tree.xpath('.//w:tcW', namespaces=tree.nsmap):
tc_w.getparent().remove(tc_w)
Warning! This approach works only for tables that should autofit window (check out this link for details).
I think, this won't work for everyone, so I haven't made a pull request. Probably, the right way is to walk through all cells of a table and update its' individual widths with corresponding <w:gridCol>
value.
Source files
sorry, but is this the solution to keep rendered table has the same column widths in template docs file? and how can I use this code?
Hi, @retsyo!
this the solution to keep rendered table has the same column widths in template docs file?
All dynamically generated columns via {%tc for %}
loop will have the same width. Already present columns will stay as is.
and how can I use this code?
If I remember correctly, this is the path that I've taken to add this workaround:
from docxtpl import DocxTemplate
class DocxTemplateWithWorkaround(DocxTemplate):
# Add the workaround after the original `fix_tables` here:
def fix_tables(self, xml):
tree = super().fix_tables(xml)
for tc_w in tree.xpath('.//w:tcW', namespaces=tree.nsmap):
tc_w.getparent().remove(tc_w)
return tree
# After that, you can use `DocxTemplateWithWorkaround` the same way as you did before:
doc = DocxTemplateWithWorkaround("my_word_template.docx")
context = { 'company_name' : "World company" }
doc.render(context)
doc.save("generated_doc.docx")