Uploading media files to your Flask application

Uploading media files to your Flask application

In this tutorial, you'll be taken through the easy steps required to upload a media file to your Flask applications.

Prerequisite

We'll be building on the simple application built in part 1 of this series. I believe you can recreate that setup by yourself now.

If you are new to the series, do well to check out part 1 before proceeding. Let's get started!!!

Configurations

The first thing to do is to create the Configuration class that will handle the following

i) location where the uploaded files will be stored ii) secret key iii) allowed file extensions iv) limiting the size of the file that can be uploaded.

static/uploads directory

Create a directory called static in the core directory. Then create an uploads directory in the static directory. This is where your media files will be stored. You can choose to change the name of the directories if you choose to.

.env

Since we'll be dealing with forms. We need to ensure that we provide our secret key as an environmental variable to ensure that the application doesn't become vulnerable through the form post requests.

Create a .env file in the root repository and place your secret key in it

SECRET_KEY = put-your-own-secret-secret-key-here

config

Create a config.py file in the base directory

import os
from dotenv import load_dotenv 

load_dotenv()
basedir = os.path.abspath(os.path.dirname(__file__))

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY')
    UPLOAD_FOLDER = os.path.join(basedir, 'core/static/uploads')
    ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
    MAX_CONTENT_LENGTH = 16 * 1024 * 1024

The secret key is loaded from the environment file .env and assigned to the SECRET_KEY variable.

Next, the value assigned to the UPLOAD_FOLDER variable is the path to the uploads folder created earlier on.

The allowed extensions coupled with the maximum content length(size) of media files that can be uploaded are also specified here.

init

Next, you need to import the Configuration class and configure the app variable with it. This assigns all the configuration settings to the application.

from flask import Flask
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

from core import views

views

from flask import render_template,flash,request,redirect
from core import app
from werkzeug.utils import secure_filename
from config import Config
import os

@app.route('/', methods=['POST','GET'])
def index():
    greeting="Hello there, Ace"

    if request.method == 'POST':
        file = request.files['file']
        if file.filename == '':
            flash('No file was selected')
            return redirect(request.url)
        elif file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(Config.UPLOAD_FOLDER, filename))
            flash('Image has been successfully uploaded')
            return redirect('/')
        else:
            flash('Allowed media types are - png, jpg, jpeg, gif')
            return redirect(request.url)
    else:
        return render_template('index.html', greet=greeting)


def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in Config.ALLOWED_EXTENSIONS

Let's go through the code above:

The os module for path configuration, Configuration class and flash function to display messages, request method & redirect function to handle page redirects are all imported at the top of the file.

The secure_filename function is required to handle unclear or malicious file names. It ensures that the file names are always clean and flat.

The default HTTP method is GET so the POST method needs to be added to the app.route function.

After confirming that a POST request method was made, request.files['file'] is used to confirm that the data of a file input with the name attribute of file is included in the submitted form data and an error message is flashed if the condition evaluates to false

The submitted data which is the uploaded media name + extension type is then passed as an argument to the allowed_file function where it is split into name of file and extension. The allowed_file function ensures that only a file with the permitted extension is processed and uploaded.

Next, the secure_filename function is called with the filename as an argument. It helps to ensure that a file with a malicious filename is not saved in the application.

If all the checks are passed successfully, the uploaded media file is saved in the specified folder which in your case should be static/uploads.

index html

To test the file upload functionality, you need to make an upgrade to the index html page as well.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Test HTML</title>
    </head>
    <body>
        <h1>{{greet}}</h1>

        {% with messages = get_flashed_messages() %}
              {% if messages %}
                <ul class="flashes">
                {% for message in messages %}
                      <li>{{ message }}</li>
                {% endfor %}
                </ul>
              {% endif %}
        {% endwith %}

        <form method= "post" enctype=multipart/form-data>
            <input type=file name=file>
            <input type=submit value=Upload>
        </form>
    </body>
</html>

The newly added lines surrounded in curly braces allow the flash messages to be rendered on the page in case an error occurs while uploading the file.

The enctype attribute assigned the value multipart/form-data is always used when files need to be uploaded via the form.

The file input has the name attribute, file which the view function uses to confirm that a file was submitted together with the form.

You can now run your application to test the whole setup:

flask run

You'll notice that when you try to submit the form without selecting an image, you get an error message notifying you that No file was selected.

Then when you finally do the right thing; and you upload an image, you get the message Image has been successfully uploaded. Now go to the folder that was created in the static directory core\static\uploads. You'll see the image file you just uploaded.

Congratulations, we have come to the end of the tutorial. I believe you can now easily set up your flask applications to have file upload functionality. You can choose to make changes to the setup such as changing the allowed extensions, maximum content length, or the location of your uploads directory. Cheers!!

Bonus: To use the image file, you can store the filename in your database after the image has been stored in the uploads folder, then Query the db for the filename and pass it to the render function.

<img src="{{ url_for('static', filename=upload/'your filename') }}">

When the page is rendered, the your filename variable then gets replaced with the result of the db query for the stored filename and, your image is displayed.

If you have any questions, feel free to drop them as a comment or send me a message on Linkedin or Twitter and I'll ensure I respond as quickly as I can. Ciao 👋