Last time, we covered adding merge fields to a Word document and using Python to get the names of all merge fields across multiple documents. If you need a refresher, check it out. Otherwise, let’s get to it.
Setting Up
We previously wrote a function that returns a list of all the merge fields from all .docx documents in the current directory. Let’s adjust this function slightly to instead allow the user to indicate which document to populate with data. Don’t forget to pip install docx-mailmerge if you didn’t do that last time.
import mailmerge
def get_merge_fields_from_a_specific_document():
doc_name = raw_input("Populate which document? ")
with mailmerge.MailMerge(doc_name+".docx") as document:
results = list(document.get_merge_fields())
results.insert(0, doc_name)
return results
This function could be improved by printing the available .docx files in the directory (maybe [f for f in os.listdir('.') if os.path.isfile(f) and ".docx" in f]?) or adding error handling, but right now we’re just setting up, so let’s keep it simple. The line results.insert(0, doc_name) puts the name of the user-selected document as the first item in the returned list. We’re going to need this info later.
We’ll use the same documents we used last time:
doc1.docx



doc2.docx



This means that the user can input either “doc1” or “doc2” in the above function without throwing an error. doc1 thus returns ['doc1', 'CityStateZip', 'Name', 'Address'] and doc2 returns ['doc2', 'PurchasePrice', 'ShipDate', 'InvoiceNumber'].
Populating Our Document
So now what? We need to get the data we want to put into the document from the user, then actually merge that data into the document. One function can handle all of this:
import os
def generate_document(merge_fields):
# Get absolute path of document we are generating
file_dir = os.path.dirname(__file__) # get path to current directory
doc_name = merge_fields.pop(0) # pop off name of document from list
file_name = doc_name + ".docx" # add .docx extension to document name
absolute_path = os.path.join(file_dir, file_name) # boom, absolute path
# Get the data that we are going to be merging from the user
# Put data in a dictionary for merging
merge_data = {} # create an empty dictionary to hold the merge data
for item in merge_fields:
merge_data[item] = raw_input("What is the %s? " % item)
# For each merge field, add it as a key and get value from user
# Merge our data into the document
document = mailmerge.MailMerge(absolute_path) # create a mailmerge object
document.merge(**merge_data) # use the merge function with ** and our dict
output_path = os.path.join(file_dir, "GeneratedDocument.docx")
document.write(output_path) # write the document to the path we specified
See how easy it is? Note that we need our data to be in a dictionary, then the money line is document.merge(**merge_data), which does all the work for us of inserting the data from our dictionary into the document. We need to use the document.write() to actually save our new document as well.
That’s it! Building out what we’ve done in the last two posts, it should be easy to write a simple script to accept user input and output it into a merged .docx file. If you have any questions, feel free to post below.