Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
305 views
in Technique[技术] by (71.8m points)

blank data field in python mailmerge project

I am just trying to have a play with creating a simple mailmerge application in python. So I have two text files. One is for names and the other has places. The names are:

Aang
Zuko
Appa
Katara
Sokka
Momo
Uncle Iroh
Toph
Brian
Toby
Donna
Petra Verkaik
Ava Price

in another file name invited_places.txt. I have the following:

Bristol
London
Plymouth
Cardiff
Swansea
Glasgow
Belfast
Twickenham
New York
New Orleans
Paris
Bridgend
Manchester

So that I can make this more dynamic this is what I have written.

PLACEHOLDER = "[name]"
ADDRESS = "[place]"
 
with open("./Input/Names/invited_names.txt") as names_files:
    names = names_files.readlines()
    # print(names)
with open("./Input/Places/invited_places.txt") as places_files:
    places = places_files.readlines()
    # print(places)
 
with open("./Input/Letters/starting_letter.txt") as letter_file:
    letter_contents = letter_file.read()
 
    for name in names:
        stripped_name = name.strip()
        new_letter = letter_contents.replace(PLACEHOLDER, stripped_name)
 
        for place in places:
            stripped_place = place.strip()
            new_letter = letter_contents.replace(ADDRESS, stripped_place)
            
        with open(f"./Output/ReadyToSend/letter_for_{stripped_name}.txt",mode="w") as completed_letter:
            completed_letter.write(new_letter)

Unfortunately, when the letters print out I only get the place name.

Dear [name],

You are invited to my birthday this Saturday. Thanks for travelling from Manchester

Hope you can make it!

Brian

Not sure if a better solution would be to use dictionaries. Any help would be appreciated.

question from:https://stackoverflow.com/questions/65923270/blank-data-field-in-python-mailmerge-project

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To start with, all your recipients are always travelling from Manchester; this is because your places list is looped through in it's entirety for each recipient name, and the document is saved AFTER the loop.

Recipient names are being switched from the place name, but when you are assigning the address in your second for loop, you are using the original letter template instead of the template modified when applying the name, the assignment of new_letter is replaced with the original letter_contents.

This would be resolved by swapping:

new_letter = letter_contents.replace(ADDRESS, stripped_place)

with

new_letter = new_letter.replace(ADDRESS, stripped_place)

Your idea of using dictionaries instead of lists is a good one. After dealing with countless mailmerge projects, one of the most difficult and necessary problems is ensuring all client details are always kept in sync. I would assign each recipient a unique ID to tie data in to. Reading both data fields into a dictionary under the same key will make it easier when you start dealing with big datasets and large numbers of fields.

An example of this, using defaultDict:

from collections import defaultdict

PLACEHOLDER = "[name]"
ADDRESS = "[place]"

fieldMapper = defaultdict(dict)


with open("invited_names.txt") as names_files:
    names = names_files.readlines()

with open("invited_places.txt") as places_files:
    places = places_files.readlines()

 
with open("starting_letter.txt") as letter_file:
    letter_contents = letter_file.read()
    docID = 0 # create a document ID
    for name in names:
        stripped_name = name.strip()
        fieldMapper[docID]['name']=stripped_name
        docID +=1
        
    docID = 0
    for place in places:
        stripped_place = place.strip()
        fieldMapper[docID]['address']=stripped_place
        docID +=1

    for document,fields in fieldMapper.items(): # run through each recipient / Doc ID in dictionary
        new_letter = letter_contents.replace(ADDRESS, fields.get('address'))
        new_letter = new_letter.replace(PLACEHOLDER, fields.get('name'))
        
        with open(f"letter_for_{fields.get('name')}.txt",mode="w") as completed_letter:
            completed_letter.write(new_letter)

If at all possible, I would add resiliency to your source data to make it difficult to mix up different fields of recipient information. As it is, if a blank line was entered halfway through your data, any further data would be out of sync. This could be accomplished by either having one source data file with comma separated values (or any other delimiter), or using a delimited recipient ID in both text files to ensure customer records will always be kept in sync. Reading CSV files in Python


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...