File: index.rst

package info (click to toggle)
python-docx-template 0.20.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 2,404 kB
  • sloc: python: 1,742; makefile: 163
file content (533 lines) | stat: -rw-r--r-- 19,182 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
.. python-docx-template documentation master file, created by
   sphinx-quickstart on Thu Mar 12 17:32:17 2015.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to python-docx-template's documentation!
================================================

.. rubric:: Quickstart

To install using pip::

    pip install docxtpl

or using conda::

    conda install docxtpl --channel conda-forge

Usage::

    from docxtpl import DocxTemplate

    doc = DocxTemplate("my_word_template.docx")
    context = { 'company_name' : "World company" }
    doc.render(context)
    doc.save("generated_doc.docx")

Introduction
------------

This package uses 2 major packages :

- python-docx for reading, writing and creating sub documents
- jinja2 for managing tags inserted into the template docx

python-docx-template has been created because python-docx is powerful for creating documents but not for modifying them.

The idea is to begin to create an example of the document you want to generate with microsoft word, it can be as complex as you want :
pictures, index tables, footer, header, variables, anything you can do with word.
Then, as you are still editing the document with microsoft word, you insert jinja2-like tags directly in the document.
You save the document as a .docx file (xml format) : it will be your .docx template file.

Now you can use python-docx-template to generate as many word documents you want from this .docx template and context variables you will associate.

Jinja2-like syntax
------------------

As the Jinja2 package is used, one can use all jinja2 tags and filters inside the word document.
Nevertheless there are some restrictions and extensions to make it work inside a word document:

Restrictions
++++++++++++

The usual jinja2 tags, are only to be used inside the same run of a same paragraph, it can not be used across several paragraphs, table rows, runs.
If you want to manage paragraphs, table rows and a whole run with its style, you must use special tag syntax as explained in next chapter.

**Note:**

a 'run' for Microsoft Word is a sequence of characters with the same style.
For example, if you create a paragraph with all characters of the same style,
MS Word will create internally only one 'run' in the paragraph. Now,
if you put in bold a text in the middle of this paragraph,
word will transform the previous 'run' into 3 different 'runs' (normal - bold - normal).

Extensions
++++++++++

Tags
....

In order to manage paragraphs, table rows, table columns, runs, special syntax has to be used::

   {%p jinja2_tag %} for paragraphs
   {%tr jinja2_tag %} for table rows
   {%tc jinja2_tag %} for table columns
   {%r jinja2_tag %} for runs

By using these tags, python-docx-template will take care to put the real jinja2 tags (without the `p`, `tr`, `tc` or `r`) at the right place into the document's xml source code.
In addition, these tags also tell python-docx-template to **remove** the paragraph, table row, table column or run where the tags are located.

For example, if you have this kind of template::

   {%p if display_paragraph %}
   One or many paragraphs
   {%p endif %}

The first and last paragraphs (those containing ``{%p ... %}`` tags) will never appear in generated docx, regardless of the ``display_paragraph`` value.

Here only::

   One or many paragraphs

will appear in generated docx if ``display_paragraph`` is True, otherwise, no paragraph at all are displayed.

**IMPORTANT :** Always put space after a starting tag delimiter and a space before the ending one :

Avoid::

   {%if something%}
   {%pif display_paragraph%}

Use instead::

   {% if something %}
   {%p if display_paragraph %}

**IMPORTANT** : Do not use ``{%p``, ``{%tr``, ``{%tc`` or ``{%r`` twice in the same
paragraph, row, column or run. Example :

Do not use this::

   {%p if display_paragraph %}Here is my paragraph {%p endif %}

But use this instead in your docx template::

   {%p if display_paragraph %}
   Here is my paragraph
   {%p endif %}

This syntax is possible because MS Word considers each line as a new paragraph (if you do not use SHIFT-RETURN).

Display variables
.................

As part of jinja2, one can used double braces::

   {{ <var> }}

if ``<var>`` is a string, ``\n``, ``\a``, ``\t`` and ``\f`` will be translated respectively into newlines, new paragraphs, tabs and page breaks

But if ``<var>`` is a RichText_ object, you must specify that you are changing the actual 'run'::

   {{r <var> }}

Note the ``r`` right after the opening braces.

**VERY IMPORTANT :** Variables must not contains characters like ``<``, ``>`` and ``&`` unless using Escaping_

**IMPORTANT :** Always put space after a starting var delimiter and a space before the ending one :

Avoid::

   {{myvariable}}
   {{rmyrichtext}}

Use instead::

   {{ myvariable }}
   {{r myrichtext }}

Comments
........

You can add jinja-like comments in your template::

   {#p this is a comment as a paragraph #}
   {#tr this is a comment as a table row #}
   {#tc this is a comment as a table cell #}

See tests/templates/comments_tpl.docx for an example.

Split and merge text
....................

* You can merge a jinja2 tag with previous line by using  ``{%-``
* You can merge a jinja2 tag with next line by using ``-%}``

A text containing Jinja2 tags may be unreadable if too long::

   My house is located {% if living_in_town %} in urban area {% else %} in countryside {% endif %} and I love it.

One can use *ENTER* or *SHIFT+ENTER* to split a text like below, then use ``{%-`` and ``-%}`` to tell docxtpl to merge the whole thing::

   My house is located
   {%- if living_in_town -%}
    in urban area
   {%- else -%}
    in countryside
   {%- endif -%}
    and I love it.

**IMPORTANT :**  Use an unbreakable space (*CTRL+SHIFT+SPACE*) when a space is wanted at line beginning or ending.

**IMPORTANT 2 :** ``{%- xxx -%}`` tags must be alone in a line : do not add some text before or after on the same line.

Escaping delimiters
...................

In order to display ``{%``, ``%}``, ``{{`` or ``}}``, one can use::

   {_%, %_}, {_{ or  }_}

Tables
......

Spanning
~~~~~~~~

You can span table cells horizontally in two ways, by using ``colspan`` tag (see tests/dynamic_table.py)::

   {% colspan <var> %}

`<var>` must contain an integer for the number of columns to span. See tests/test_files/dynamic_table.py for an example.

You can also span horizontally within a for loop (see tests/horizontal_merge.py)::

   {% hm %}

You can also merge cells vertically within a for loop (see tests/vertical_merge.py)::

   {% vm %}

Cell color
~~~~~~~~~~

There is a special case when you want to change the background color of a table cell, you must put the following tag at the very beginning of the cell::

   {% cellbg <var> %}

`<var>` must contain the color's hexadecimal code *without* the hash sign

.. _RichText:

RichText
--------

When you use ``{{ <var> }}`` tag in your template, it will be replaced by the string contained within `var` variable.
BUT it will keep the current style.
If you want to add dynamically changeable style, you have to use both : the ``{{r <var> }}`` tag AND a ``RichText`` object within `var` variable.
You can change color, bold, italic, size, font and so on, but the best way is to use Microsoft Word to define your own *character* style
( Home tab -> modify style -> manage style button -> New style, select ‘Character style’ in the form ), see example in `tests/richtext.py`
Instead of using ``RichText()``, one can use its shortcut : ``R()``

The ``RichText()`` or ``R()`` offers newline, new paragraph, and page break features : just use ``\n``, ``\a``, ``\t`` or ``\f`` in the
text, they will be converted accordingly.

There is a specific case for font: if your font is not displayed correctly, it may be because it is defined
only for a region. To know your region, it requires a little work by analyzing the document.xml inside the docx template (this is a zip file).
To specify a region, you have to prefix your font name this that region and a column::

   ch = RichText('测试TEST', font='eastAsia:微软雅黑')

**Important** : When you use ``{{r }}`` it removes the current character styling from your docx template, this means that if
you do not specify a style in ``RichText()``, the style will go back to a microsoft word default style.
This will affect only character styles, not the paragraph styles (MSWord manages this 2 kind of styles).

**IMPORTANT** : Do not use 2 times ``{{r`` in the same run. Use RichText.add()
method to concatenate several strings and styles at python side and only one
``{{r`` at template side.

**Important** : ``RichText`` objects are rendered into xml *before* any filter is applied
thus ``RichText`` are not compatible with Jinja2 filters. You cannot write in your template something like ``{{r <var>|lower }}``.
Only solution is instead to do any filtering into your python code when creating the ``RichText`` object.

Hyperlink with RichText
+++++++++++++++++++++++

You can add an hyperlink to a text by using a Richtext with this syntax::

   tpl=DocxTemplate('your_template.docx')
   rt = RichText('You can add an hyperlink, here to ')
   rt.add('google',url_id=tpl.build_url_id('http://google.com'))

Put ``rt`` in your context, then use ``{{r rt}}`` in your template

RichTextParagraph
-----------------

If you want to change paragraph properties, you can use ``RichTextParagraph()`` or ``RP()`` object.
It must be added to the template by using ``{{p <var> }}``.
Have a look to the example here ``tests/richtextparagraph.py``.


Inline image
------------

You can dynamically add one or many images into your document (tested with JPEG and PNG files).
just add ``{{ <var> }}`` tag in your template where ``<var>`` is an instance of doxtpl.InlineImage::

   myimage = InlineImage(tpl, image_descriptor='test_files/python_logo.png', width=Mm(20), height=Mm(10))

You just have to specify the template object, the image file path and optionally width and/or height.
For height and width you have to use millimeters (Mm), inches (Inches) or points(Pt) class.
Please see tests/inline_image.py for an example.

Sub-documents
-------------

A template variable can contain a complex subdoc object and be built from scratch using python-docx document methods.
To do so, first, get the sub-document object from your template object, then use it by treating it as a python-docx document object.
See example in `tests/subdoc.py`.

Since docxtpl V0.12.0, it is now possible to merge an existing .docx as a subdoc, just specify its path when
calling method `new_subdoc()` ::

   tpl = DocxTemplate('templates/merge_docx_master_tpl.docx')
   sd = tpl.new_subdoc('templates/merge_docx_subdoc.docx')

   context = {
       'mysubdoc': sd,
   }

   tpl.render(context)
   tpl.save('output/merge_docx.docx')

In the above example, the content of 'templates/merge_docx_subdoc.docx' will be inserted into the parent document in place of the declared
variable `{{ mysubdoc }}`.

See `tests/merge_docx.py` for full code.

.. _Escaping:

Escaping
--------

By default, no escaping is done : read carefully this chapter if you want to avoid crashes during docx generation.

When you use a ``{{ <var> }}``, under the hood, you are modifying an **XML** word document, this means you cannot use all chars,
especially ``<``, ``>`` and ``&``. In order to use them, you must escape them. There are 4 ways :

   *  ``context = { 'var':R('my text') }`` and ``{{r <var> }}`` in the template (note the ``r``),
   *  ``context = { 'var':'my text'}`` and ``{{ <var>|e }}`` in your word template
   *  ``context = { 'var':escape('my text')}`` and ``{{ <var> }}`` in the template.
   *  enable autoescaping when calling render method: ``tpl.render(context, autoescape=True)`` (default is autoescape=False)

See tests/escape.py example for more informations.

Another solution, if you want to include a listing into your document, that is to escape the text and manage ``\n``, ``\a``, and ``\f``
you can use the ``Listing`` class :

in your python code::

   context = { 'mylisting':Listing('the listing\nwith\nsome\nlines \a and some paragraph \a and special chars : <>&') }

in your docx template just use ``{{ mylisting }}``

With ``Listing()``, you will keep the current character styling (except after a ``\a`` as you start a new paragraph).

Replace docx pictures
---------------------

It is not possible to dynamically add images in header/footer, but you can change them.
The idea is to put a dummy picture in your template, render the template as usual, then replace the dummy picture with another one.
You can do that for all medias at the same time.
Note: the aspect ratio will be the same as the replaced image
Note2 : Specify the filename that has been used to insert the image in the docx template (only its basename, not the full path)

Syntax to replace dummy_header_pic.jpg::

   tpl.replace_pic('dummy_header_pic.jpg','header_pic_i_want.jpg')


The replacement occurs in headers, footers and the whole document's body.


Replace docx medias
-------------------

It is not possible to dynamically add other medias than images in header/footer, but you can change them.
The idea is to put a dummy media in your template, render the template as usual, then replace the dummy media with another one.
You can do that for all medias at the same time.
Note: for images, the aspect ratio will be the same as the replaced image
Note2 : it is important to have the source media files as they are required to calculate their CRC to find them in the docx.
(dummy file name is not important)

Syntax to replace dummy_header_pic.jpg::

   tpl.replace_media('dummy_header_pic.jpg','header_pic_i_want.jpg')


WARNING : unlike replace_pic() method, dummy_header_pic.jpg MUST exist in the template directory when rendering and saving the generated docx. It must be the same
file as the one inserted manually in the docx template.
The replacement occurs in headers, footers and the whole document's body.

Replace embedded objects
------------------------

It works like medias replacement, except it is for embedded objects like embedded docx.

Syntax to replace embedded_dummy.docx::

   tpl.replace_embedded('embedded_dummy.docx','embedded_docx_i_want.docx')


WARNING : unlike replace_pic() method, embedded_dummy.docx MUST exist in the template directory when rendering and saving the generated docx. It must be the same
file as the one inserted manually in the docx template.
The replacement occurs in headers, footers and the whole document's body.

Note that `replace_embedded()` may not work on other documents than embedded docx.
Instead, you should use zipname replacement::

   tpl.replace_zipname(
       'word/embeddings/Feuille_Microsoft_Office_Excel1.xlsx',
       'my_excel_file.xlsx')

The zipname is the one you can find when you open docx with WinZip, 7zip (Windows) or unzip -l (Linux).
The zipname starts with "word/embeddings/". Note that the file to be replaced is renamed by MSWord, so you have to guess a little bit...

This works for embedded MSWord file like Excel or PowerPoint file, but won't work for others like PDF, Python or even Text files :
For these ones, MSWord generate an oleObjectNNN.bin file which is no use to be replaced as it is encoded.

Get Defined Variables
---------------------

In order to get the missing variables after rendering use ::

   tpl=DocxTemplate('your_template.docx')
   tpl.render(context_dict)
   set_of_variables = tpl.get_undeclared_template_variables()

**IMPORTANT** : You may use the method before rendering to get a set of keys you need, e.g. to be prompted to a user or written in a file for manual processing.

Multiple rendering
------------------

Since v0.15.0, it is possible to create ``DocxTemplate`` object once and call
``render(context)`` several times. Note that if you want to use replacement
methods like ``replace_media()``, ``replace_embedded()`` and/or ``replace_zipname()``
during multiple rendering, you will have to call ``reset_replacements()``
at rendering loop start.



Microsoft Word 2016 special cases
---------------------------------

MS Word 2016 will ignore ``\t`` tabulations. This is special to that version.
Libreoffice or Wordpad do not have this problem. The same thing occurs for line
beginning with a jinja2 tag providing spaces : They will be ignored.
To solve these problem, the solution is to use Richtext::

   tpl.render({
       'test_space_r' : RichText('          '),
       'test_tabs_r': RichText(5*'\t'),
   })

And in your template, use the {{r notation::

   {{r test_space_r}} Spaces will be preserved
   {{r test_tabs_r}} Tabs will be displayed


Jinja custom filters
--------------------

``render()`` accepts ``jinja_env`` optional argument : you may pass a jinja environment object.
By this way you will be able to add some custom jinja filters::

    from docxtpl import DocxTemplate
    import jinja2

    def multiply_by(value, by):
       return value * by

    doc = DocxTemplate("my_word_template.docx")
    context = { 'price_dollars' : 5.00 }
    jinja_env = jinja2.Environment()
    jinja_env.filters['multiply_by'] = multiply_by
    doc.render(context,jinja_env)
    doc.save("generated_doc.docx")

Then in your template, you will be able to use::

    Euros price : {{ price_dollars|multiply_by(0.88) }}


Command-line execution
----------------------

One can use `docxtpl` module directly on command line to generate a docx from a template and a json file as a context::

   usage: python -m docxtpl [-h] [-o] [-q] template_path json_path output_filename

   Make docx file from existing template docx and json data.

   positional arguments:
     template_path    The path to the template docx file.
     json_path        The path to the json file with the data.
     output_filename  The filename to save the generated docx.

   optional arguments:
     -h, --help       show this help message and exit
     -o, --overwrite  If output file already exists, overwrites without asking
                      for confirmation
     -q, --quiet      Do not display unnecessary messages


See tests/module_execute.py for an example.

Examples
--------

The best way to see how it works is to read examples, they are located in `tests/` directory.
Docx test templates are in `tests/templates/`. To generate final docx files::

   cd tests/
   python runtests.py

Generated files are located in `tests/output` directory.

If you are not sure about your python environment, python-docx-template provides Pipfiles
for that::

   pip install pipenv (if not already done)
   cd python-docx-template (where Pipfiles are)
   pipenv install --python 3.6 -d
   pipenv shell
   cd tests/
   python runtests.py

Share
-----

If you like this project, please rate and share it here : http://rate.re/github/elapouya/python-docx-template


.. rubric:: Functions index

.. currentmodule:: docxtpl

.. rubric:: Functions documentation

.. automodule:: docxtpl
   :members:


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`