Flask - File Uploading
Flask – File Uploading
Section titled “Flask – File Uploading”Handling file uploads is a common requirement for web applications. Flask makes this process relatively simple.
The basic workflow involves:
- An HTML form with
method="POST"and, crucially,enctype="multipart/form-data". This encoding allows file data to be sent along with the form. - An
<input type="file" name="some_name">element within the form for the user to select a file. - A Flask view function that handles the POST request.
- Accessing the uploaded file data via the
request.filesdictionary-like object. - Saving the file securely to a designated location on the server.
When a file is uploaded, Flask (using the underlying Werkzeug library) initially saves it to a temporary location on the server. Your view function then retrieves this file object from request.files using the name attribute specified in the HTML input tag (e.g., request.files['file']).
The file object obtained from request.files has a save() method which you can use to save the file permanently. It’s crucial to sanitize the filename provided by the user before saving it to prevent directory traversal attacks. Werkzeug provides the secure_filename() function for this purpose. It removes potentially harmful characters (like ../) from the filename.
You can configure Flask to manage uploads more effectively:
| Configuration Key | Description |
|---|---|
app.config['UPLOAD_FOLDER'] | The path to the directory where uploaded files should be stored. |
app.config['MAX_CONTENT_LENGTH'] | The maximum allowed file size in bytes (e.g., 16 * 1024 * 1024 for 16 MB). Flask will reject requests with larger payloads. |
Let’s create a simple file upload example.
First, the HTML form (templates/upload.html):
<!doctype html><html><head> <title>Upload File</title></head><body> <h2>Select a file to upload</h2> <form action="{{ url_for('handle_upload') }}" method="POST" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Upload"> </form></body></html>This form will POST the selected file to the URL associated with the handle_upload view function.
Now, the Flask application (app.py):
import osfrom flask import Flask, render_template, request, redirect, url_for, flashfrom werkzeug.utils import secure_filename
# Define the path for uploaded filesUPLOAD_FOLDER = 'uploads'# Define allowed file extensions (optional but recommended for security)ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDERapp.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB limitapp.config['SECRET_KEY'] = 'super-secret-key' # Needed for flashing messages
# Ensure the upload folder existsif not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER)
# Helper function to check allowed file extensionsdef allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')def index(): # Redirect to the upload form page return redirect(url_for('show_upload_form'))
@app.route('/upload')def show_upload_form(): # Render the page with the upload form return render_template('upload.html')
@app.route('/uploader', methods=['POST'])def handle_upload(): if 'file' not in request.files: flash('No file part in the request', 'danger') return redirect(request.url)
file = request.files['file']
if file.filename == '': flash('No selected file', 'warning') return redirect(url_for('show_upload_form'))
if file and allowed_file(file.filename): # Sanitize the filename filename = secure_filename(file.filename) # Create the full save path save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) try: file.save(save_path) flash(f'File "{filename}" uploaded successfully!', 'success') # You could redirect to a page showing the uploaded file or a success message return redirect(url_for('show_upload_form')) except Exception as e: flash(f'An error occurred while saving the file: {e}', 'danger') return redirect(url_for('show_upload_form')) elif file and not allowed_file(file.filename): flash('File type not allowed', 'danger') return redirect(url_for('show_upload_form')) else: # Should not happen with the checks above, but as a fallback flash('An unknown error occurred', 'danger') return redirect(url_for('show_upload_form'))
if __name__ == '__main__': app.run(debug=True)Key points in the Python code:
- UPLOAD_FOLDER: Defines where files are saved.
- ALLOWED_EXTENSIONS/allowed_file(): Basic validation to only accept certain file types. This is important for security.
- MAX_CONTENT_LENGTH: Limits upload size.
- SECRET_KEY: Required by Flask for flashing messages.
- Folder Creation: Ensures the upload directory exists.
handle_upload()function:-
- Checks if the file part exists in the request (
'file' in request.files).
- Checks if the file part exists in the request (
-
- Checks if a filename was actually submitted (
file.filename == '').
- Checks if a filename was actually submitted (
-
- Checks if the file type is allowed using
allowed_file().
- Checks if the file type is allowed using
-
- Uses
secure_filename()to get a safe filename.
- Uses
-
- Constructs the full path using
os.path.join().
- Constructs the full path using
-
- Calls
file.save()to store the file.
- Calls
-
- Uses
flash()to provide feedback to the user.
- Uses
-
- Redirects back to the upload form (or potentially a success page).
To run this, save the code, create a templates folder with upload.html inside, and run python app.py. Navigate to http://localhost:5000/ (which redirects to /upload). You’ll see the file input field and submit button. Choose a file (respecting the allowed extensions and size limit) and click ‘Upload’. If successful, the file will be saved in the uploads directory (created in the same folder as app.py), and a success message will appear.
Important Security Considerations:
- Never trust user input: Always validate filenames (
secure_filename) and file types (allowed_file). Consider more robust checks like inspecting file headers (magic numbers) if necessary. - Storage Location: Avoid saving uploaded files directly within your web application’s public directory if they don’t need to be directly served. Consider a separate, non-web-accessible directory or cloud storage (like AWS S3, Google Cloud Storage).
- Resource Limits: Set
MAX_CONTENT_LENGTHto prevent denial-of-service attacks via huge uploads. - Serving Files: Be careful when serving uploaded files back to users, especially if they contain executable content or HTML/JavaScript. Set appropriate
Content-Typeheaders and potentiallyContent-Disposition: attachmentto force downloads. - Permissions: Ensure the web server process has write permissions to the
UPLOAD_FOLDERbut minimal permissions elsewhere.