Using python-docx-template to dynamically create bookmarks and links to them in Word documents
I am using the python-docx-template module to generate docx files from a template.
You can read more about the module here: https://docs-python.ru/packages/modul-python-docx-python/modul-docx-template/
The module contains functionality for inserting external links into the document, but when I needed to create internal links according to the template (to a specific place in the document), there was no such functionality, a search on the net also did not give anything.
Here I propose my own way of inserting bookmarks (bookmarks) and links (hyperlinks) to them using python-docx-template.
Solution
The module includes a RichText() object. The add(string) method of this object creates xml code, which is placed in RichText().xml and then inserted as is into the docx document.
For example:
rt = RichText()
rt.add('TEST')
print(rt.xml)
# <w:r><w:t xml:space="preserve">TEST</w:t></w:r>
I decided to generate it myself and directly put the xml code I need in RichText().xml and it worked.
Below is an example code:
from docxtpl import DocxTemplate, RichText
def add_bookmarks_and_links(data):
for i, item in enumerate(data['articles']):
# создаем закладку
bookmark_name = f'article_{i}'
bookmark = RichText(item["title"])
bookmark.xml = f'<w:bookmarkStart w:id="" w:name="{bookmark_name}"/>' + \
bookmark.xml + \
'<w:bookmarkEnd w:id=""/>'
item['title_with_bookmark'] = bookmark
# создаем ссылку на закладку
hyperlink_start = RichText()
hyperlink_end = RichText()
hyperlink_start.xml = f'<w:hyperlink w:anchor="{bookmark_name}" w:history="1">'
hyperlink_end.xml="</w:hyperlink>"
item['hyperlink_start'] = hyperlink_start
item['hyperlink_end'] = hyperlink_end
data = {'report_title': 'Report title',
'articles': [{'title': 'Title Article 1',
'description': 'Description Article 1',
'body': 'Body Article 1'},
{'title': 'Title Article 2',
'description': 'Description Article 2',
'body': 'Body Article 2'}
]
}
template_filename="template.docx"
result_filename="result.docx"
add_bookmarks_and_links(data)
tpl = DocxTemplate(template_filename)
tpl.render(data)
tpl.save(result_filename)
The docx template file looks something like this:
{{ report_title }}
Дайджест
{% for article in articles %}
{{r article.hyperlink_start }}{{ article.title }}{{r article.hyperlink_end }}
{{ article.description }}
{% endfor %}
Полные тексты статей
{% for article in articles %}
{{ article.title_with_bookmark }}
{{ article.description }}
{{ article.body }}
{% endfor %}
As a result of executing the code, we get a document with a section of article digests, with links in the headings that lead to the full texts of the articles:
Similarly, you can insert any other xml code not supported by the python-docx-template module into the template fields.
Thank you for your attention.