Generating Custom Word Documents from Templates with Python and docxtpl
When dealing with repetitive document creation, using a template-based approach significantly reduces manual effort. The Python package docxtpl lets you load a .docx template, replace placeholders with real values, and save the result. Combined with pandas for reading tabular data, you can bulk-generate personalized documents from a single template.
Installation
pip install docxtpl pandas
Example: Generating Admission Letters
Assume you have a Word template (admission_template.docx) with placeholders wrapped in double curly braces, such as {{name}}, {{faculty}}, {{major}}, {{start_date}}, and {{end_date}}.
Your data source is a CSV file (candidates.csv) structured like this:
| name | faculty | major | start_date | end_date |
|---|---|---|---|---|
| Alice | Computer Science | AI | 2025-09-01 | 2029-06-30 |
| Bob | Computer Science | AI | 2025-09-01 | 2029-06-30 |
Step 1 – Import Libraries
from docxtpl import DocxTemplate
import pandas as pd
import os
Step 2 – Prepare Output Directory
base_dir = os.getcwd()
out_dir = os.path.join(base_dir, 'letters_output')
os.makedirs(out_dir, exist_ok=True)
Step 3 – Read Data from CSV
df = pd.read_csv(
os.path.join(base_dir, 'candidates.csv'),
encoding='utf-8'
)
# Strip whitespace from all object columns
df = df.apply(lambda col: col.str.strip() if col.dtype == 'object' else col)
Step 4 – Generate Documents in a Loop
template_path = os.path.join(base_dir, 'admission_template.docx')
# Load the template once outside the loop
tpl = DocxTemplate(template_path)
for idx, row in df.iterrows():
# Build context dictionary from the current row
context = {
'name': row['name'],
'faculty': row['faculty'],
'major': row['major'],
'start_date': row['start_date'],
'end_date': row['end_date']
}
# Render the template with current context
tpl.render(context)
# Construct output filename
save_name = f"{row['name']}_admission_letter.docx"
out_path = os.path.join(out_dir, save_name)
# Save the generated document
tpl.save(out_path)
The script iterates over each row, fills the template, and saves a personalized Word file into letters_output/. The template is loaded once; subsequent render() and save() calls reuse the same instance, which is efficient for large batches.
Important Considerations
- Encoding issues: If you encounter garbled characters, adjust the
encodingparameter (e.g.,'gbk'or'utf-8'). - Whitespace in data: Use
.str.strip()on string columns to prevent unexpected line breaks in the output. - File permissions: Insure the CSV file is not open in another program during execution.
- Template re-selection: If you see the same content in all output files, verify that you are not reloading the template inside the loop (loading after each save resets it).