Contents

File Uploads and Handling in Flask

File uploads are a common feature in web applications, whether it’s for profile pictures, documents, or other types of content. Flask makes it easy to handle file uploads, validate them for security, serve them to users, and manage file paths in a database.

Setting Up File Uploads in a Flask Application

To handle file uploads in Flask, you need to set up a form in your HTML, configure Flask to handle file uploads, and write the necessary routes to process these uploads.

Step 1: Configure Flask for File Uploads

Start by configuring your Flask application to specify the folder where uploaded files should be stored and set a limit on the file size:

				
					from flask import Flask, render_template, request, redirect, url_for, flash
import os

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads/'  # Folder to store uploaded files
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16 MB limit
app.secret_key = 'your_secret_key'

if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.makedirs(app.config['UPLOAD_FOLDER'])


				
			

Step 2: Create an HTML Form for File Uploads

In your templates folder, create an HTML form that allows users to upload files:

				
					<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload File</title>
</head>
<body>
    <h1>Upload a File</h1>
    <form method="POST" action="{{ url_for('upload_file') }}" enctype="multipart/form-data">
        <input type="file" name="file"><br><br>
        <input type="submit" value="Upload">
    </form>
    
    {% with messages = get_flashed_messages(with_categories=true) %}
      {% if messages %}
        {% for category, message in messages %}
          <div class="alert alert-{{ category }}">{{ message }}</div>
        {% endfor %}
      {% endif %}
    {% endwith %}
</body>
</html>



				
			

Step 3: Write the Route to Handle File Uploads

In your app.py, write a route that handles the file upload:

				
					from werkzeug.utils import secure_filename

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

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

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # Check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part', 'danger')
            return redirect(request.url)
        file = request.files['file']
        # If the user does not select a file, the browser may submit an empty part without filename
        if file.filename == '':
            flash('No selected file', 'danger')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            flash(f'File successfully uploaded: {filename}', 'success')
            return redirect(url_for('upload_file'))
    return render_template('upload.html')



				
			
  • allowed_file: This function checks if the file has an allowed extension (for security).
  • secure_filename: This utility function ensures that the uploaded file’s name is secure, preventing path traversal attacks.
  • file.save: This saves the file to the specified directory on the server.

Validating and Securing File Uploads

To prevent security risks, you must validate file uploads and ensure that only allowed file types are accepted.

Step 1: Validate File Type

As shown above, you can validate file types by checking the file extension using the allowed_file function. This is a basic but effective way to restrict the types of files that can be uploaded.

Step 2: Secure the Filename

Using secure_filename from werkzeug.utils ensures that the filename is safe to use on your filesystem. It strips any potentially dangerous characters and ensures that the file is saved with a safe name.

Step 3: Set Maximum File Size

By configuring MAX_CONTENT_LENGTH, you can limit the size of uploaded files, protecting your server from excessively large uploads.

				
					app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16 MB limit



				
			

If a user tries to upload a file that exceeds this limit, Flask will return a 413 Request Entity Too Large error.

Serving Uploaded Files to Users

Once files are uploaded, you might need to serve them to users, for example, displaying profile pictures or allowing users to download files.

Step 1: Serve Files Using a Static Route

Flask can serve files from the UPLOAD_FOLDER using the send_from_directory function:

				
					from flask import send_from_directory

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)



				
			

Now, users can access their uploaded files by visiting http://127.0.0.1:5000/uploads/filename.

Step 2: Link to Uploaded Files in HTML

You can create links to uploaded files in your HTML templates:

				
					<a href="{{ url_for('uploaded_file', filename='example.jpg') }}">Download Example File</a>



				
			

Storing and Managing File Paths in the Database

To keep track of uploaded files, you should store their paths in a database. This allows you to associate files with users or other entities in your application.

Step 1: Define a Model for File Storage

Create a model in app.py to store file paths:

				
					class UploadedFile(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(255), nullable=False)
    filepath = db.Column(db.String(255), nullable=False)
    upload_date = db.Column(db.DateTime, default=datetime.utcnow)

    def __repr__(self):
        return f"UploadedFile('{self.filename}', '{self.filepath}')"



				
			

Step 2: Store File Information When Uploading

Modify the upload_file route to store file information in the database after a successful upload:

				
					@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part', 'danger')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash('No selected file', 'danger')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filepath)
            # Save file info to the database
            uploaded_file = UploadedFile(filename=filename, filepath=filepath)
            db.session.add(uploaded_file)
            db.session.commit()
            flash(f'File successfully uploaded: {filename}', 'success')
            return redirect(url_for('upload_file'))
    return render_template('upload.html')



				
			

Step 3: Retrieve and Display Uploaded Files

You can retrieve and display uploaded files from the database:

				
					@app.route('/files')
def list_files():
    files = UploadedFile.query.all()
    return render_template('files.html', files=files)



				
			

In files.html, you can display the list of files:

				
					<ul>
  {% for file in files %}
    <li><a href="{{ url_for('uploaded_file', filename=file.filename) }}">{{ file.filename }}</a></li>
  {% endfor %}
</ul>



				
			

Summary

Handling file uploads in Flask involves setting up a secure and efficient upload process, validating file types, serving files to users, and storing file paths in a database. By following these steps, you can manage file uploads in your Flask applications effectively while maintaining security and organization.