LearnThatStack Ace your next interview

Flask.
Cheat sheet.

Quick reference for Flask - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

Backend Development 18-section reference ~9 min read

Summary

Flask is a lightweight, flexible Python web framework based on Werkzeug and Jinja2. It follows a minimalist philosophy, providing core web development functionality while allowing developers to choose their preferred tools and libraries. This cheatsheet covers Flask fundamentals, routing, templates, forms, database integration with SQLAlchemy, authentication, RESTful APIs, testing, and deployment best practices.

Flask Basics

Installation & Setup

pip install flask

Minimal Application

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(debug=True)

Application Factory Pattern

# app/__init__.py
def create_app(config_name='development'):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    
    # Register blueprints
    from .main import main as main_bp
    app.register_blueprint(main_bp)
    
    return app

Routing & Views

Basic Routes

@app.route('/user/<username>')
def show_user(username):
    return f'User: {username}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post: {post_id}'

HTTP Methods

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return do_login()
    return show_login_form()

URL Building

from flask import url_for

@app.route('/user/<username>')
def profile(username):
    return f'Profile: {username}'

# Usage: url_for('profile', username='john')

Blueprints

# auth.py
from flask import Blueprint

auth = Blueprint('auth', __name__, url_prefix='/auth')

@auth.route('/login')
def login():
    return 'Login page'

# main app
app.register_blueprint(auth)

Request Handling

Request Object

from flask import request

@app.route('/search')
def search():
    # Query parameters
    query = request.args.get('q', '')
    
    # Form data
    username = request.form.get('username')
    
    # JSON data
    data = request.get_json()
    
    # Files
    file = request.files['file']
    
    # Headers
    user_agent = request.headers.get('User-Agent')
    
    # Cookies
    session_id = request.cookies.get('session_id')

Response Object

from flask import make_response, jsonify

@app.route('/api/data')
def get_data():
    # JSON response
    return jsonify({'key': 'value'}), 200
    
    # Custom response
    resp = make_response('Custom response')
    resp.headers['X-Custom-Header'] = 'value'
    resp.set_cookie('session', 'abc123')
    return resp

Templates (Jinja2)

Basic Template Rendering

from flask import render_template

@app.route('/user/<name>')
def user(name):
    return render_template('user.html', name=name)

Template Syntax

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

<!-- templates/user.html -->
{% extends "base.html" %}

{% block title %}User Profile{% endblock %}

{% block content %}
    <h1>Hello {{ name|upper }}!</h1>
    
    {% if user.is_active %}
        <p>Active user</p>
    {% endif %}
    
    {% for item in items %}
        <li>{{ loop.index }}: {{ item }}</li>
    {% endfor %}
{% endblock %}

Template Filters

@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

# Usage in template: {{ name|reverse }}

Forms & Validation

Flask-WTF Forms

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # Process form data
        email = form.email.data
        return redirect(url_for('index'))
    return render_template('login.html', form=form)

CSRF Protection

# config.py
SECRET_KEY = 'your-secret-key'

# In template
<form method="POST">
    {{ form.csrf_token }}
    {{ form.email.label }} {{ form.email() }}
    {{ form.submit() }}
</form>

Database Integration

Flask-SQLAlchemy Setup

from flask_sqlalchemy import SQLAlchemy

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)

Models

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)
    
    def __repr__(self):
        return f'<User {self.username}>'

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

Database Operations

# Create tables
db.create_all()

# Add record
user = User(username='john', email='john@example.com')
db.session.add(user)
db.session.commit()

# Query
all_users = User.query.all()
user = User.query.filter_by(username='john').first()
user = User.query.get(1)  # by primary key

# Update
user.email = 'newemail@example.com'
db.session.commit()

# Delete
db.session.delete(user)
db.session.commit()

Migrations (Flask-Migrate)

flask db init
flask db migrate -m "Initial migration"
flask db upgrade

Authentication & Sessions

Flask-Login

from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'auth.login'

class User(UserMixin, db.Model):
    # ... model fields ...
    
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/login', methods=['POST'])
def login():
    user = User.query.filter_by(email=email).first()
    if user and check_password_hash(user.password, password):
        login_user(user, remember=True)
        return redirect(url_for('dashboard'))
    return 'Invalid credentials'

@app.route('/dashboard')
@login_required
def dashboard():
    return 'Welcome to dashboard'

Sessions

from flask import session

@app.route('/set_session')
def set_session():
    session['username'] = 'john'
    return 'Session set'

@app.route('/get_session')
def get_session():
    username = session.get('username', 'Guest')
    return f'Hello {username}'

RESTful APIs

Basic REST Endpoints

@app.route('/api/users', methods=['GET'])
def get_users():
    users = User.query.all()
    return jsonify([{'id': u.id, 'username': u.username} for u in users])

@app.route('/api/users/<int:id>', methods=['GET'])
def get_user(id):
    user = User.query.get_or_404(id)
    return jsonify({'id': user.id, 'username': user.username})

@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.get_json()
    user = User(username=data['username'], email=data['email'])
    db.session.add(user)
    db.session.commit()
    return jsonify({'id': user.id}), 201

@app.route('/api/users/<int:id>', methods=['PUT'])
def update_user(id):
    user = User.query.get_or_404(id)
    data = request.get_json()
    user.username = data.get('username', user.username)
    db.session.commit()
    return jsonify({'message': 'Updated'})

@app.route('/api/users/<int:id>', methods=['DELETE'])
def delete_user(id):
    user = User.query.get_or_404(id)
    db.session.delete(user)
    db.session.commit()
    return '', 204

Flask-RESTful

from flask_restful import Api, Resource, reqparse

api = Api(app)

class UserAPI(Resource):
    def get(self, id=None):
        if id:
            user = User.query.get_or_404(id)
            return {'id': user.id, 'username': user.username}
        users = User.query.all()
        return [{'id': u.id, 'username': u.username} for u in users]
    
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('username', required=True)
        parser.add_argument('email', required=True)
        args = parser.parse_args()
        # Create user logic
        return {'message': 'User created'}, 201

api.add_resource(UserAPI, '/api/users', '/api/users/<int:id>')

Error Handling

Error Handlers

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_error(e):
    db.session.rollback()
    return render_template('500.html'), 500

# API error handling
@app.errorhandler(404)
def api_not_found(e):
    return jsonify({'error': 'Resource not found'}), 404

Custom Exceptions

class ValidationError(Exception):
    pass

@app.errorhandler(ValidationError)
def handle_validation_error(e):
    return jsonify({'error': str(e)}), 400

Testing

Unit Tests

import unittest
from app import create_app, db

class UserModelCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app('testing')
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()
        
    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
        
    def test_password_hashing(self):
        u = User(username='test')
        u.set_password('cat')
        self.assertFalse(u.check_password('dog'))
        self.assertTrue(u.check_password('cat'))

Client Testing

def test_home_page(self):
    client = self.app.test_client()
    response = client.get('/')
    self.assertEqual(response.status_code, 200)
    self.assertIn(b'Welcome', response.data)

def test_login(self):
    client = self.app.test_client()
    response = client.post('/login', data={
        'email': 'test@example.com',
        'password': 'password'
    }, follow_redirects=True)
    self.assertEqual(response.status_code, 200)

Configuration & Deployment

Configuration Classes

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard-to-guess'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    
class DevelopmentConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
    
class ProductionConfig(Config):
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
    
config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

Environment Variables

# .env file
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://user:pass@localhost/dbname

# Load with python-dotenv
from dotenv import load_dotenv
load_dotenv()

Deployment (Gunicorn)

pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 "app:create_app()"

Performance & Security

Caching

from flask_caching import Cache

cache = Cache(app, config={'CACHE_TYPE': 'simple'})

@app.route('/expensive')
@cache.cached(timeout=300)
def expensive_operation():
    # Time-consuming operation
    return result

Rate Limiting

from flask_limiter import Limiter

limiter = Limiter(
    app,
    key_func=lambda: request.remote_addr,
    default_limits=["100 per hour"]
)

@app.route('/api/data')
@limiter.limit("5 per minute")
def get_data():
    return jsonify({'data': 'value'})

Security Headers

from flask_talisman import Talisman

Talisman(app, force_https=True)

# Manual headers
@app.after_request
def set_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    return response

Password Hashing

from werkzeug.security import generate_password_hash, check_password_hash

# Store password
password_hash = generate_password_hash('password123')

# Verify password
check_password_hash(password_hash, 'password123')  # Returns True

Key Concepts & Comparisons

Flask vs Django Comparison

Aspect Flask Django
Philosophy Micro-framework, minimal Full-featured, "batteries included"
Learning Curve Easier to start Steeper learning curve
Flexibility High flexibility More structured/opinionated
Built-in Features Minimal (Werkzeug, Jinja2) ORM, Admin, Auth, etc.
Use Cases APIs, small-medium apps Large, complex applications

Context Objects in Flask

Context Objects Available Scope Usage
Application Context current_app, g Per application Config access, app-level data
Request Context request, session Per HTTP request Request data, user sessions
# Application context example
with app.app_context():
    print(current_app.config['SECRET_KEY'])
    g.db = get_database_connection()

# Request context (automatic in view functions)
@app.route('/profile')
def profile():
    username = request.args.get('username')
    user_id = session.get('user_id')
    return f'Profile for {username}'

Blueprint Organization Benefits

Benefit Description Example
Modularity Organize related routes auth.py, api.py, admin.py
Reusability Share blueprints across projects Authentication blueprint
Team Development Multiple developers work on different modules Feature-based separation
URL Prefixing Group routes under common prefix /api/v1/, /admin/

Database Connection Patterns

# Flask-SQLAlchemy pattern (recommended)
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    
# Automatic connection management
@app.route('/users')
def get_users():
    users = User.query.all()  # Connection handled automatically
    return jsonify([u.username for u in users])

# Manual session management
@app.teardown_appcontext
def close_database(error):
    if hasattr(g, 'db'):
        g.db.close()

Request-Response Cycle

  1. HTTP Request: Client sends request to Flask application
  2. URL Routing: Flask matches URL pattern to view function
  3. Before Request: @app.before_request handlers execute
  4. View Function: Matched function processes request
  5. Template Rendering: Jinja2 renders templates (if applicable)
  6. After Request: @app.after_request handlers modify response
  7. HTTP Response: Response sent back to client

File Upload Implementation

from werkzeug.utils import secure_filename
import os

ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg'}

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':
        file = request.files['file']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return 'File uploaded successfully'
    return 'Upload failed'

WSGI and Deployment

Concept Description Example
WSGI Web Server Gateway Interface Standard Python web interface
Development Server Built-in Flask server flask run (not for production)
Production Server WSGI-compatible server Gunicorn, uWSGI, Waitress
Reverse Proxy Handle static files, SSL Nginx, Apache

Middleware Implementation Patterns

# Before request (authentication check)
@app.before_request
def require_auth():
    if request.endpoint and request.endpoint.startswith('admin'):
        if 'user_id' not in session:
            return redirect(url_for('auth.login'))

# After request (add security headers)
@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    return response

# Error handling
@app.errorhandler(404)
def not_found(error):
    if request.path.startswith('/api/'):
        return jsonify({'error': 'Resource not found'}), 404
    return render_template('404.html'), 404

Quick Reference Commands

# Create virtual environment
python -m venv venv
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows

# Install Flask
pip install flask

# Run development server
flask run
export FLASK_APP=app.py
export FLASK_ENV=development

# Database commands
flask db init
flask db migrate
flask db upgrade

# Run tests
python -m pytest
python -m unittest discover

# Freeze requirements
pip freeze > requirements.txt

Essential Flask Extensions

Category Extension Purpose Usage
Database Flask-SQLAlchemy ORM and database toolkit db.Model, db.session
Database Flask-Migrate Database migrations flask db migrate
Authentication Flask-Login User session management @login_required, current_user
Forms Flask-WTF Forms and CSRF protection FlaskForm, CSRF tokens
API Development Flask-RESTful REST API framework Resource classes
Authentication Flask-JWT-Extended JWT token authentication @jwt_required
Communication Flask-Mail Email functionality Send emails
Performance Flask-Caching Caching support @cache.cached()
Security Flask-Limiter Rate limiting API endpoint protection
CORS Flask-CORS Cross-origin requests Enable CORS headers

Performance Optimization Strategies

Strategy Implementation Impact
Database Connection Pooling SQLAlchemy engine configuration Reduced connection overhead
Query Optimization Eager loading, proper indexing Faster database operations
Caching Flask-Caching, Redis Reduced computation time
Static File Serving CDN, Nginx Faster asset delivery
Response Compression Gzip middleware Reduced bandwidth usage
Pagination Limit query results Better memory usage
Async Views (Flask 2.0+) async def for I/O operations Better concurrency
Application Profiling Flask-Profiler, cProfile Identify bottlenecks

Security Best Practices Checklist

Essential Security Measures

  • HTTPS Only: Force SSL/TLS in production environment
  • Secure Cookies: Set secure=True, httponly=True for session cookies
  • CSRF Protection: Use Flask-WTF for form protection
  • Input Validation: Validate and sanitize all user inputs
  • SQL Injection Prevention: Use SQLAlchemy parameterized queries
  • Password Security: Use werkzeug.security for hashing
  • Security Headers: Implement X-Frame-Options, CSP, etc.
  • Dependency Management: Keep all packages updated
  • Environment Variables: Store secrets in environment, not code
  • Authentication & Authorization: Implement proper access controls
  • Rate Limiting: Protect API endpoints from abuse
  • Security Logging: Log authentication and authorization events

Security Implementation Examples

# Secure session configuration
app.config.update(
    SECRET_KEY='your-secret-key',
    SESSION_COOKIE_SECURE=True,      # HTTPS only
    SESSION_COOKIE_HTTPONLY=True,    # No JS access
    SESSION_COOKIE_SAMESITE='Lax'    # CSRF protection
)

# Security headers
@app.after_request
def security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

Thread Safety & Concurrency

Aspect Flask Behavior Best Practice
Request Handling Each request gets own context No shared mutable state
Database Connections Thread-local sessions Use Flask-SQLAlchemy
Global Variables Use g object for request data Avoid module-level globals
Caching Thread-safe cache backends Redis, Memcached

Production Deployment Best Practices

✅ Server Setup: Use production WSGI server (Gunicorn, uWSGI)
✅ Environment: Set proper environment variables, use .env files
✅ Security: Enable HTTPS, set security headers, validate inputs
✅ Performance: Implement caching, use CDN, optimize database queries
✅ Monitoring: Configure logging, error tracking, health checks
✅ Scalability: Use reverse proxy (Nginx), implement rate limiting

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime