File Uploads – PARSE CSV FILE UPLOAD AS LIST OF DICTIONARIES IN FLASK WITHOUT SAVING

Developers often need to design web sites that allow users to upload a CSV file. Usually there is no reason to save the actual CSV file since the data will processed and/or stored in a database once uploaded. However, many if not most, PYTHON methods of parsing CSV data requires the data to be read in as a file. This may present a bit of a headache if you are using FLASK for web development.

Suppose our CSV has a header row and looks like the following:

h1,h2,h3
'yellow','orange','blue'
'green','white','black'
'orange','pink','purple'

Now, suppose the html form to upload a file is as follows:

<form action="upload.html" method="post" enctype="multipart/form-data">
    <input type="file" name="fileupload" id="fileToUpload">
    <input type="submit" value="Upload File" name="submit">
</form>

Since no one wants to reinvent the wheel you decide to IMPORT csv into your FLASK script. There is no guarantee that people will upload the csv file with the columns in the correct order. If the csv file has a header row, then with the help of the csv.DictReader method you can read the CSV file as a list of dictionaries, keyed by the entries in the header row. However, csv.DictReader needs a file and does not directly accept strings. You may think you need to use FLASK methods to first save the uploaded file, get the new file name and location, open it using csv.DictReader, and then delete the file. Seems like a bit of a waste.

Luckily, we can get the file contents as a string and then split the string up by terminated lines. The csv method csv.DictReader will accept this as a substitute to a file. The following code demonstrates how this can be accomplished without temporarily saving the file.

@application.route('upload.html',methods = ['POST'])
def upload_route_summary():
    if request.method == 'POST':

        # Create variable for uploaded file
        f = request.files['fileupload']  

        #store the file contents as a string
        fstring = f.read()
        
        #create list of dictionaries keyed by header row
        csv_dicts = [{k: v for k, v in row.items()} for row in csv.DictReader(fstring.splitlines(), skipinitialspace=True)]

        #do something list of dictionaries
    return "success"

The variable csv_dicts is now the following list of dictionaries:

   csv_dicts = 
    [
        {'h1':'yellow','h2':'orange','h3':'blue'},
        {'h1':'green','h2':'white','h3':'black'},
        {'h1':'orange','h2':'pink','h3':'purple'}
    ]

In case you are new to PYTHON, you can access data like the following:

csv_dicts[1]['h2'] = 'white'
csv_dicts[0]['h3'] = 'blue'

Other solutions involve importing the io module and use the io.Stream method. I feel that this is a more straightforward approach. I believe the code is a little easier to follow than using the io method. This approach is specific to the example of parsing an uploaded CSV file.

if you want to reproduce, please indicate the source:
File Uploads – PARSE CSV FILE UPLOAD AS LIST OF DICTIONARIES IN FLASK WITHOUT SAVING - CodeDay