How to Upload a File in Flask

Many web apps or websites require uploading some sort of files such as PDFs, Images, Text files among others. If using flask for your back end, this may not be very straight forward to implement but its not very difficult.

In this article, we are going to demonstrate how to configure file uploads using Flask by creating a profile picture upload section.

Prerequisites Packages

These can be installed using pip command

-Flask
-Flask-Reuploaded

You also need to know how to set up a basic flask app. See this guide on how to get started with Flask

Creating a route for uploads

First we start by creating a route for our upload. We’ll call it /uploads/pp

@app.route('/uploads/pp/', methods = ['GET', 'POST'])
def upload_photo():
    return redirect(url_for('viewprofile'))

The route above returns a function called viewprofile( ). In my app, this function returns a file called profile.html. You can choose to change the return type above to suit your own application.

Creating the form to allow uploads

Next, we’ll create a html file and copy in the following content.

<div class="col-lg-4 order-lg-1 text-center">
            <form role="form" action="/uploads/pp/" method="post" enctype=multipart/form-data>
            <img src="{{photo_location}}" class="mx-auto img-fluid img-circle d-block" alt="avatar">
            <label class="custom-file">
               <input type="file" id="file" name="photo" class="custom-file-input">
                <span class="custom-file-control">Choose File</span>
            </label>
            <button type="submit" class="btn btn-outline-success btn-sm" >Upload Photo</button>
        </div>

This is a simple form that will provide us with a means to upload our desired image file and then it will display it on your browser.

Note: Am using Bootstrap CSS on the above form. Feel free to use your own or remove all CSS altogether.

Changing our /upload/pp/ route

Now, we need to make changes to our route so as to implement full functionality. Basically, what we want to achieve is:

  • Save our profile picture in a folder called profiles under static folder
  • From a database, get a unique id for the user and use it as a file name so as to distinguish various users profile photos saved in profiles folder.
  • Save the profile picture location in MySQL database
  • Display the profile picture on the browser once successfully uploaded.

To achieve these, replace the route we created at first with the code below

@app.route('/uploads/pp/', methods = ['GET', 'POST'])
def upload_photo():

    email == '[email protected]'

    if request.method == 'POST' and 'photo' in request.files:

        #select unique user id from database to use as profile picture name
        cur = dbconnection.cursor()
        cur.execute('SELECT id FROM members WHERE email = %s', email)
        member = cur.fetchone()
        (id, *others) = member

        #assign the member unique id as the file name for our uploaded image
        #we are also getting some URLs to the image we will use in our profile.html file
        profilepic_name = str(id)+'.png'
        profilepic_url = '/static/images/profiles/'+profilepic_name
        workingdir = os.path.abspath(os.getcwd())
        fullprofilepic_url = workingdir + profilepic_url


        #remove similar file name if it already exists. If this is not done, the new file 
        #uploaded will be named diffrently as a file name with the required name alreay exists
        if os.path.isfile(fullprofilepic_url) == True:
            os.remove(fullprofilepic_url)


        #save file name on disk and show success message
        photos.save(request.files['photo'], folder=None, name=profilepic_name)
        flash("Success! Profile photo uploaded successfully.", 'success')


        #save the image url on database for futire use
        cur = dbconnection.cursor()
        cur.execute('UPDATE members SET pic_url = %s WHERE email = %s', (profilepic_url, email))
        dbconnection.commit()
        cur.close()


        #redirect to profile page.the function viewprofile should return a html file.
        return redirect(url_for('viewprofile'))

Explaining the route

Behind the scenes there is a MySQL database where information about users who would want to upload profile photos is stored. From this database, we obtain user id as in line 10 – 12 of the code above. The id is a unique field therefore using the value of this field guarantees us to always get unique file names for images uploaded.

Lines 16 – 19 allow us to create the name of the file.

Line 24 – 25 will first remove a file with the given name before another is uploaded. This is useful if you want to update your profile picture. Without this line, if say my file name is called 23.png, then if I upload another one without deleting 23.png, flask will name the new file 23_1.png which will then mean it cannot be displayed.

Lines 34 – 37 save the picture URL to the database. This can then be used on other routes on the flask app.

Leave a Reply

Your email address will not be published. Required fields are marked *