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.py
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.py
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.py
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, 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 👋
Top comments (0)