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.