File Handling

Back

Loading concept...

πŸ“ Flask File Handling: Your Digital Mailroom

Imagine you run a magical mailroom. People send you packages (files), and your job is to store them safely and deliver them back when asked. Flask’s file handling is exactly like this!


🎯 What We’ll Learn

Think of Flask as your helpful assistant who knows how to:

  • Deliver files to visitors (send_file)
  • Fetch files from specific rooms (send_from_directory)
  • Clean up messy package labels (secure filename)
  • Organize storage rooms (file storage paths)
  • Hand back stored packages (serving uploaded files)

πŸ“¬ The send_file Function

What Is It?

send_file is like a personal delivery person. You tell them: β€œGo get this exact file and hand it to the visitor.”

Simple Example

from flask import send_file

@app.route('/download')
def download_report():
    return send_file(
        'reports/sales.pdf',
        as_attachment=True
    )

What’s Happening?

graph TD A["User clicks Download"] --> B["Flask gets request"] B --> C["send_file finds the file"] C --> D[File sent to user's browser] D --> E["Download starts!"]

Key Options

Option What It Does Example
as_attachment=True Forces download dialog User saves the file
download_name Changes the filename download_name='my_report.pdf'
mimetype Tells browser file type mimetype='image/png'

Real-Life Use

@app.route('/invoice/<int:id>')
def get_invoice(id):
    path = f'invoices/inv_{id}.pdf'
    return send_file(
        path,
        as_attachment=True,
        download_name=f'Invoice_{id}.pdf'
    )

πŸ—‚οΈ The send_from_directory Function

Why Is This Different?

Imagine your mailroom has many rooms (folders). send_from_directory says: β€œGo to THIS specific room and find THIS file.”

Why use it? It’s safer! It checks that no one tricks you into leaving that room.

Simple Example

from flask import send_from_directory

@app.route('/uploads/<filename>')
def serve_upload(filename):
    return send_from_directory(
        'uploads',
        filename
    )

The Safety Shield

graph TD A["User asks for: ../../secrets.txt"] --> B["send_from_directory checks"] B --> C{Is this safe?} C -->|NO - Bad path!| D["❌ Blocked"] C -->|YES - Safe file| E["βœ… File sent"]

Example with Options

@app.route('/photos/<name>')
def get_photo(name):
    return send_from_directory(
        app.config['PHOTO_FOLDER'],
        name,
        as_attachment=False
    )

πŸ’‘ Pro Tip: Use send_from_directory when serving user uploads. It prevents sneaky path attacks!


πŸ›‘οΈ Secure Filename Handling

The Problem

What if someone uploads a file called ../../../etc/password? That’s trying to escape your upload folder and access system files! Scary!

The Solution: secure_filename

from werkzeug.utils import secure_filename

bad_name = "../../../evil.txt"
safe_name = secure_filename(bad_name)
# Result: "evil.txt"

What It Fixes

Dangerous Input After secure_filename
../../../file.txt file.txt
my file.pdf my_file.pdf
<script>bad.js scriptbad.js
ζ—₯本θͺž.png _.png

Complete Upload Example

from werkzeug.utils import secure_filename
import os

ALLOWED = {'png', 'jpg', 'pdf'}

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

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['document']
    if file and allowed_file(file.filename):
        safe = secure_filename(file.filename)
        file.save(
            os.path.join(
                app.config['UPLOAD_FOLDER'],
                safe
            )
        )
        return 'Uploaded!'
    return 'Invalid file', 400

πŸ“ File Storage Paths

Why Paths Matter

Your mailroom needs organized storage rooms. Wrong paths = lost files!

Setting Up Your Storage

import os

# Get your app's home directory
BASE_DIR = os.path.dirname(
    os.path.abspath(__file__)
)

# Create upload folder path
UPLOAD_FOLDER = os.path.join(
    BASE_DIR,
    'uploads'
)

# Tell Flask about it
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# Make sure folder exists!
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

The Path Building Blocks

graph TD A["BASE_DIR"] --> B["/home/app/myproject"] B --> C["+ &&#35;39;uploads&&#35;39;"] C --> D["/home/app/myproject/uploads"] D --> E["+ &&#35;39;photo.jpg&&#35;39;"] E --> F["/home/app/myproject/uploads/photo.jpg"]

Common Path Patterns

# For uploads
upload_path = os.path.join(
    app.config['UPLOAD_FOLDER'],
    filename
)

# For static files
static_path = os.path.join(
    app.static_folder,
    'images',
    'logo.png'
)

# Check if file exists
if os.path.exists(upload_path):
    return send_file(upload_path)

πŸš€ Serving Uploaded Files

The Complete Picture

Now let’s put it all together! Users upload files, you store them safely, then serve them back.

Complete Working Example

from flask import Flask, request
from flask import send_from_directory
from werkzeug.utils import secure_filename
import os

app = Flask(__name__)

# Configuration
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max

ALLOWED = {'png', 'jpg', 'gif', 'pdf'}

def allowed_file(name):
    return '.' in name and \
        name.rsplit('.', 1)[1].lower() \
        in ALLOWED

# Upload endpoint
@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return 'No file!', 400

    file = request.files['file']
    if file.filename == '':
        return 'No selected file', 400

    if file and allowed_file(file.filename):
        safe_name = secure_filename(
            file.filename
        )
        file.save(
            os.path.join(
                app.config['UPLOAD_FOLDER'],
                safe_name
            )
        )
        return f'Saved as {safe_name}'

    return 'File type not allowed', 400

# Serve endpoint
@app.route('/files/<name>')
def serve_file(name):
    return send_from_directory(
        app.config['UPLOAD_FOLDER'],
        name
    )

The Complete Flow

graph TD A["πŸ‘€ User selects file"] --> B["πŸ“€ Upload request"] B --> C["πŸ” Check file type"] C --> D["πŸ›‘οΈ Secure filename"] D --> E["πŸ’Ύ Save to uploads/"] E --> F["βœ… Return success"] G["πŸ‘€ User wants file"] --> H["πŸ“₯ Request /files/name"] H --> I["πŸ” send_from_directory"] I --> J["πŸ“ Find in uploads/"] J --> K["βœ… Send to user"]

🎁 Quick Reference

Task Function Key Point
Send any file send_file() Full path needed
Send from folder send_from_directory() Safer, checks path
Clean filename secure_filename() Always use on uploads
Build paths os.path.join() Works on all systems
Check exists os.path.exists() Prevent 404 errors

🌟 Remember This!

  1. Always use secure_filename() on uploaded files
  2. Use send_from_directory() for user uploads
  3. Set MAX_CONTENT_LENGTH to limit file sizes
  4. Check file extensions before saving
  5. Create folders with os.makedirs(exist_ok=True)

πŸŽ‰ You did it! You now know how to safely handle files in Flask. Your digital mailroom is secure and ready for action!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.