Rely on

See the documentation for installing dependencies

  1. docxtpl

Document address: docxtpl. Readthedocs. IO/en/latest/note: there are a lot of its making example instance, recommended to download the project running locally to learn all kinds of usage scenarios.

  1. plotly

Note: To export still images, you need to install the Kaleido package. You can install PIP directly. For details, see the Plotly documentation.

  1. Jinja2

Its files will not be released…


Here I will do a summary of all the libraries and versions I depend on to avoid incompatibility between versions:

  • Docxtpl = = 0.11.2
  • Kaleido = = 0.1.0 from
  • Plotly = = 4.14.1
  • Jinja2 = = 2.10.3
  • LXML = = 4.3.2
  • Python – docx = = 0.8.10

Requirement Scenario Analysis

Recently, there is a new interface requirement that requires the back end to provide a report export interface. This interface can export word documents in two content forms, including chart data: statistical tables and line charts, bar charts and pie charts of data analysis.

As the exported content of Word is basically fixed in format and description, only data and charts will change dynamically. Therefore, after investigation, I decided to use docxTPL library +Jinja2 template syntax to fill the content of the prepared Word template document and generate the final document. The DocxTPL library relies on Python-Docx and can be used to render dictionaries in jinja2 templates and insert text, tables, images, etc.

Although we can generate charts from data when using Word, python-Docx library itself does not have an API interface for generating charts, so chart data can only be inserted into static images. After research and testing, plotly was selected to generate graphs and export image files.

Many schemes on the Internet use the method of Pyecharts + Pyecharts-Snapshot, which actually uses headless browser to render screenshots and obtain static image files. In the actual test, the efficiency of exporting images is relatively low, and relies on node environment PhantomJS, so the use experience is not good, so it is not recommended.

Prepare the template DOCX document

First, I used Jinja2 to make the Word document as the basic template, but it seems that the file cannot be uploaded. Here is a simple screenshot of the example. The following is the template content edited in the sample DOCx file, which has included the filling method used in my actual project: Jinja2 syntax is used for general fill, circular fill, and conditional block determination. If you are not familiar with Jinja2, you can look up the documentation to see how this template syntax is used.

Example plotly chart static file generation code

This is a brief demonstration of how to use Plotly to generate local files or write static file data to ByteIO. Please refer to the documentation for other apis related to graphs. The official documentation is quite detailed.

import plotly.graph_objects as go
from io import BytesIO

def get_line_image(x, y) :
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=x, y=y, text=y, textposition="top center", mode="lines+markers"))
    image_io = BytesIO()
    fig.write_image(image_io, format="jpeg")
    return image_io
Copy the code

Since I do not need the image file generated locally, so just need to write the file object to BytesIO return, you can also according to the need to directly write_image(file=”a.png”) to generate images and return to the local file path.

Docxtpl template library example of use

Finally, we will write the assembled filling data into the DOCX document to generate the required Word document. Let’s go straight to the sample code.

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm


Initialize the template processing object
tpl = DocxTemplate("./ sample template file.docx")

The graph static file object is generated by calling the example Plotly method above
line_charts = get_line_image(x=["Class"."Class 2"."Three"], y=["75"."80"."82"])

Example dictionary data to be filled, where key corresponds to the fill name in the Word template, and the image needs to call the InlineImage class
context = {
    "average": 80."class": "Class 2, Grade 3"."table": [{"name": "Little red"."gender": "Male"."grade": 80},
              {"name": "White"."gender": "Male"."grade": 79},
              {"name": "Black"."gender": "Female"."grade": 81}]."line_image": InlineImage(tpl, line_charts, width=Mm(164), height=Mm(82.5})),Start rendering the context data into the template file
tpl.render(context=context)
# save: ByteIO objects can still be written here, since the back end does not need to save the file, you can still save the final file locally using save(' a.dox ') if necessary
# file_io = BytesIO()
tpl.save("Sample result document.docx")

Copy the code

Here is a screenshot of the output from the above example:

The last

As long as you refer to the above once, you can redesign the code structure and adjust the template file format, image size and so on according to the actual needs, basically can achieve the template class word document export requirements, if you have any questions and suggestions, also welcome to leave a message, I hope this document can help you.