Flask Cheat Sheet: A Comprehensive Quick-Reference Guide
Flask is a lightweight WSGI micro-framework for Python, designed to make getting started quick and easy, with the ability to scale up to complex applications. It was created by Armin Ronacher and is classified as a micro-framework because it does not require particular tools or libraries — it has no database abstraction layer, form validation, or any other pre-existing third-party library that provides common functions .
Flask's core philosophy is built on two pillars: the Werkzeug WSGI toolkit and the Jinja2 templating engine. Together, they give you URL routing, request/response handling, a development server, and powerful template rendering — all without the overhead of a full-stack framework.
The framework follows the MVC pattern loosely, giving you the flexibility to structure your app as you see fit. Flask's minimalist approach means you only add what you need — Flask-SQLAlchemy for databases, Flask-WTF for forms, Flask-Login for authentication, and so on.
Footnotes
-
Flask Official Documentation — The primary reference for Flask's API, patterns, and best practices including routing, contexts, and deployment guidelines. ↩
Flask Cheatsheet for Beginners
Application Setup & Configuration
Every Flask application begins by creating an application instance:
1from flask import Flask 2 3app = Flask(__name__) 4 5@app.route('/') 6def home(): 7 return 'Hello, World!' 8 9if __name__ == '__main__': 10 app.run(debug=True, port=5000)
The __name__ argument tells Flask where to look for templates, static files, and other resources. When debug=True, Flask enables the interactive debugger and auto-reloads on code changes — never use this in production .
| Configuration Method | Syntax | Use Case |
|---|---|---|
| From dictionary | app.config['DEBUG'] = True | Quick single-value setting |
| From object | app.config.from_object('config.DevConfig') | Class-based configs |
| From file | app.config.from_pyfile('config.py') | File-based configs |
| From environment | app.config.from_envvar('APP_SETTINGS') | 12-factor app pattern |
| From JSON | app.config.from_json('config.json') | JSON-based configs |
Key built-in configuration variables:
| Variable | Default | Description |
|---|---|---|
DEBUG | False | Enable debug mode |
SECRET_KEY | None | Used for sessions & CSRF protection |
SESSION_COOKIE_SECURE | False | Set secure flag on session cookies |
MAX_CONTENT_LENGTH | None | Max request size in bytes |
JSON_SORT_KEYS | True | Sort JSON response keys |
Footnotes
-
Flask Official Documentation — The primary reference for Flask's API, patterns, and best practices including routing, contexts, and deployment guidelines. ↩
Never Set DEBUG=True in Production
The Flask debugger allows execution of arbitrary Python code in the browser. Exposing DEBUG=True in production is a critical security vulnerability that can lead to remote code execution. Always use environment variables to control this setting.
Routing & URL Dispatching
Routing maps URLs to Python functions. Flask uses the route decorator to connect URL patterns to handler functions.
1# Basic routes 2@app.route('/') 3def index(): 4 return 'Index Page' 5 6@app.route('/hello') 7def hello(): 8 return 'Hello, World' 9 10# Dynamic routes with variable rules 11@app.route('/user/<username>') 12def show_user(username): 13 return f'User: {username}' 14 15@app.route('/post/<int:post_id>') 16def show_post(post_id): 17 return f'Post ID: {post_id}' 18 19@app.route('/path/<path:subpath>') 20def show_subpath(subpath): 21 return f'Subpath: {subpath}'
Variable converters:
| Converter | Type | Example |
|---|---|---|
string | Any text (default) | <name> |
int | Positive integers | <int:id> |
float | Positive floats | <float:price> |
path | Text with slashes | <path:filepath> |
uuid | UUID strings | <uuid:task_id> |
HTTP method binding:
1@app.route('/api/data', methods=['GET', 'POST']) 2def handle_data(): 3 if request.method == 'POST': 4 return 'Created', 201 5 return 'Data list', 200
url_for() — the proper way to build URLs:
1from flask import url_for 2 3url_for('show_user', username='alice') # /user/alice 4url_for('static', filename='style.css') # /static/style.css
Request-Response Lifecycle in Flask
- 1Step 1
The browser or API client sends an HTTP request to the Flask development server. The request includes a method (GET, POST, etc.), URL, headers, and optional body.
- 2Step 2
Werkzeug receives the raw HTTP request and wraps it into a WSGI-compatible environ dictionary. This is the interface between the web server and Flask.
- 3Step 3
Flask's URL map compares the request path against all registered route rules. If a match is found, the corresponding view function is identified. If no match exists, a 404 error is raised. URL rule precedence follows the most specific match .
Footnotes
-
Flask Official Documentation — The primary reference for Flask's API, patterns, and best practices including routing, contexts, and deployment guidelines. ↩
-
- 4Step 4
Any functions registered with
@app.before_requestrun in order. These can perform authentication checks, database setup, or terminate the request early by returning a response. - 5Step 5
The matched view function runs. It has access to the
requestobject with all incoming data. The function processes business logic and returns a response — either a string, a dict (auto-converted to JSON), a tuple, or aResponseobject. - 6Step 6
Functions registered with
@app.after_requestrun on the response object. They can modify headers, log data, or transform the response. The@app.teardown_requesthooks run even if an exception occurred. - 7Step 7
Flask converts the return value to a proper HTTP
Responseobject (if not already one), adds status code and headers, and sends it back through Werkzeug to the client.
The Request Object
Flask's request context provides access to all incoming request data through the global request object:
1from flask import request 2 3# Request method & URL 4request.method # 'GET', 'POST', etc. 5request.url # Full URL 6request.path # '/api/users' 7request.base_url # URL without query string 8request.args # ImmutableMultiDict of query params 9 10# Form & JSON data 11request.form # Form data (POST) 12request.json # Parsed JSON body 13request.data # Raw body bytes 14 15# Headers & cookies 16request.headers # Dict-like headers 17request.cookies # Dict of cookies 18 19# Files 20request.files # MultiDict of uploaded files 21file = request.files['upload'] 22file.save(f'/uploads/{file.filename}')
| Attribute | Type | Description |
|---|---|---|
request.args | ImmutableMultiDict | URL query parameters |
request.form | ImmutableMultiDict | Form body data |
request.json | dict or None | Parsed JSON payload |
request.files | MultiDict | Uploaded file objects |
request.values | CombinedMultiDict | Merged args + form |
request.cookies | dict | Client cookies |
request.headers | EnvironHeaders | Request headers |
Templates with Jinja2
Flask uses Jinja2 for rendering HTML. Templates should be stored in a templates/ directory.
1from flask import render_template 2 3@app.route('/profile/<username>') 4def profile(username): 5 return render_template('profile.html', name=username, age=25)
Template syntax cheat sheet:
1<!-- Variable interpolation --> 2<h1>Hello, {{ name }}!</h1> 3 4<!-- Filters --> 5<p>{{ name|capitalize }}</p> 6<p>{{ price|round(2) }}</p> 7<p>{{ content|truncate(100) }}</p> 8<p>{{ html_content|safe }}</p> 9<p>{{ items|length }}</p> 10 11<!-- Conditionals --> 12{% if user.is_authenticated %} 13 <p>Welcome back, {{ user.name }}</p> 14{% elif user.is_guest %} 15 <p>Browse as guest</p> 16{% else %} 17 <p>Please log in</p> 18{% endif %} 19 20<!-- Loops --> 21{% for item in items %} 22 <li>{{ loop.index }}: {{ item }}</li> 23{% endfor %} 24 25<!-- Macro (reusable template function) --> 26{% macro render_button(text, type='primary') %} 27 <button class="btn btn-{{ type }}">{{ text }}</button> 28{% endmacro %} 29 30{{ render_button('Submit') }} 31{{ render_button('Delete', 'danger') }}
Template inheritance:
1<!-- base.html --> 2<!DOCTYPE html> 3<html> 4<head> 5 <title>{% block title %}Default Title{% endblock %}</title> 6 {% block head %}{% endblock %} 7</head> 8<body> 9 {% block content %}{% endblock %} 10 {% block scripts %}{% endblock %} 11</body> 12</html> 13 14<!-- child.html --> 15{% extends "base.html" %} 16{% block title %}Child Page{% endblock %} 17{% block content %} 18 <h1>Child Content Here</h1> 19{% endblock %}
| Jinja2 Feature | Syntax | Purpose |
|---|---|---|
| Variable | {{ var }} | Render value |
| Tag | {% tag %} | Logic/control |
| Comment | {# comment #} | Template comment (not in output) |
| Extends | {% extends "base.html" %} | Inherit parent template |
| Block | {% block name %}...{% endblock %} | Define overridable sections |
| Include | {% include "nav.html" %} | Insert another template |
| Macro | {% macro name() %}...{% endmacro %} | Reusable template function |
| Set | {% set x = 5 %} | Assign template variable |
Use url_for() Instead of Hardcoded URLs
Always use url_for('endpoint_name', arg=val) in templates to generate URLs. If you later change a route's URL pattern, url_for() automatically updates — but hardcoded URLs break silently. Example: href="{{ url_for('profile', username=user.name) }}" is preferred over href="/profile/{{ user.name }}".
Flask Hooks & Contexts
Flask Extensions by Popularity (Approximate Downloads/Week)
Most commonly used Flask extensions in the ecosystem
Databases with Flask-SQLAlchemy
Flask-SQLAlchemy is the most popular database extension. It provides an ORM layer and simplifies database configuration.
1from flask_sqlalchemy import SQLAlchemy 2from flask_migrate import Migrate 3 4app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db' 5app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 6 7db = SQLAlchemy(app) 8migrate = Migrate(app, db) 9 10# Model definition 11class User(db.Model): 12 __tablename__ = 'users' 13 14 id = db.Column(db.Integer, primary_key=True) 15 username = db.Column(db.String(80), unique=True, nullable=False) 16 email = db.Column(db.String(120), unique=True, nullable=False) 17 created_at = db.Column(db.DateTime, server_default=db.func.now()) 18 19 # Relationship 20 posts = db.relationship('Post', backref='author', lazy=True) 21 22 def __repr__(self): 23 return f'<User {self.username}>' 24 25class Post(db.Model): 26 id = db.Column(db.Integer, primary_key=True) 27 title = db.Column(db.String(200), nullable=False) 28 content = db.Column(db.Text) 29 user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
Common SQLAlchemy column types & queries:
1# Column types available 2db.String(80) db.Text db.Integer 3db.Float db.Boolean db.DateTime 4db.Date db.LargeBinary db.Numeric 5db.Enum db.JSON db.ARRAY 6 7# Query operations 8User.query.all() # All records 9User.query.filter_by(username='alice').first() # Filter by exact 10User.query.filter(User.email.endswith('@org.com')).all() # SQL-like 11User.query.order_by(User.created_at.desc()).limit(10).all() 12User.query.paginate(page=1, per_page=20) # Pagination 13 14# CRUD Operations 15user = User(username='bob', email='bob@org.com') 16db.session.add(user) 17db.session.commit() 18 19user.username = 'bob_updated' 20db.session.commit() 21 22db.session.delete(user) 23db.session.commit()
SQLALCHEMY_DATABASE_URI Format Matters
Double-check your connection string format. Common mistakes include missing the /// for SQLite (which is file-based) vs // for remote databases.
- SQLite:
sqlite:////absolute/path/to/db.sqlite(3 slashes for relative, 4 for absolute) - PostgreSQL:
postgresql://user:password@localhost:5432/mydb - MySQL:
mysql://user:password@localhost/mydb - Never commit database URLs with credentials — use environment variables instead.
Building a Flask REST API Endpoint
- 1Step 1
Use
@app.route()with explicit HTTP methods. For REST APIs, be specific about allowed methods:1from flask import Blueprint 2 3api_bp = Blueprint('api', __name__, url_prefix='/api/v1') 4 5@api_bp.route('/users', methods=['GET', 'POST']) 6@api_bp.route('/users/<int:user_id>', methods=['GET', 'PUT', 'DELETE']) 7def users(user_id=None): 8 pass - 2Step 2
Extract and validate input from the request:
1from flask import request 2 3# For GET: query parameters 4page = request.args.get('page', 1, type=int) 5per_page = request.args.get('per_page', 10, type=int) 6 7# For POST/PUT: JSON body 8data = request.get_json() 9username = data.get('username') 10email = data.get('email') - 3Step 3
Interact with the database and apply validation/rules:
1if request.method == 'POST': 2 if User.query.filter_by(email=email).first(): 3 return {'error': 'Email already exists'}, 409 4 user = User(username=username, email=email) 5 db.session.add(user) 6 db.session.commit() 7 return {'id': user.id, 'username': user.username}, 201 8 9if request.method == 'GET': 10 if user_id: 11 user = User.query.get_or_404(user_id) 12 return {'id': user.id, 'username': user.username} 13 users = User.query.paginate(page=page, per_page=per_page) 14 return {'items': [u.to_dict() for u in users.items], 15 'total': users.total} - 4Step 4
Always return consistent JSON with appropriate HTTP status codes:
1# 200 OK — Successful retrieval or update 2# 201 Created — Resource created successfully 3# 204 No Content — Successful deletion 4# 400 Bad Request — Invalid input 5# 404 Not Found — Resource doesn't exist 6# 409 Conflict — Duplicate resource 7# 422 Unprocessable — Validation failure
Flask Core Concepts
Flask Request Processing Lifecycle
Request Arrives
1Client sends HTTP request; Werkzeug wraps it into a WSGI environ dict."
App & Request Contexts Pushed
2Flask pushes the application context then the request context onto the context stack."
URL Matching
3The URL map resolves the request path to a registered view function endpoint."
Before-Request Hooks
4@app.before_request functions execute — can reject or augment the request early."
View Function Runs
5The matched view function executes business logic and returns a value (string, dict, Response, tuple)."
After-Request Hooks
6@app.after_request functions modify the response (e.g., add security headers)."
Teardown Hooks
7@app.teardown_request and @app.teardown_appcontext clean up resources (close DB, etc.)."
Response Sent
8The Response object is sent back through Werkzeug as an HTTP response to the client."
Blueprints — Modular Application Architecture
Blueprints let you organize your application into distinct, reusable components — essential for anything beyond a single-file app.
1# auth/routes.py 2from flask import Blueprint, render_template 3 4auth_bp = Blueprint('auth', __name__, 5 template_folder='templates', 6 static_folder='static', 7 url_prefix='/auth') 8 9@auth_bp.route('/login') 10def login(): 11 return render_template('auth/login.html') 12 13@auth_bp.route('/register') 14def register(): 15 return render_template('auth/register.html')
1# app.py — Register the blueprint 2from auth.routes import auth_bp 3 4app.register_blueprint(auth_bp) 5# Routes now available at /auth/login, /auth/register 6 7# Register with additional prefix 8app.register_blueprint(auth_bp, url_prefix='/v2/auth')
Recommended project structure:
myapp/ ├── app/ │ ├── __init__.py # create_app() factory │ ├── models.py │ ├── auth/ │ │ ├── __init__.py │ │ ├── routes.py # auth_bp blueprint │ │ ├── forms.py │ │ └── templates/auth/ │ ├── api/ │ │ ├── __init__.py │ │ ├── routes.py # api_bp blueprint │ │ └── schemas.py │ ├── main/ │ │ ├── __init__.py │ │ ├── routes.py # main_bp blueprint │ │ └── templates/main/ │ ├── static/ │ └── templates/ │ └── base.html ├── migrations/ ├── config.py ├── requirements.txt └── run.py
Advanced Flask Topics
Flask Authentication Flow
Environment Variables for Configuration
Use python-dotenv with a .flaskenv file for Flask CLI settings and a .env file for secrets. Never commit .env to version control.
.flaskenv (committed to repo):
FLASK_APP=app FLASK_ENV=development
.env (git-ignored):
SECRET_KEY=a-random-secret-key DATABASE_URL=postgresql://user:pass@localhost/db
Access in code: app.config['SECRET_KEY'] or os.getenv('SECRET_KEY')
Knowledge Check
What does the @app.route() decorator do in Flask?
Explore Related Topics
Blockchain Developer Skills: A Comprehensive Guide
This comprehensive guide maps the roadmap, skills, and resources required to become a competent blockchain developer.
- Core skill tree spans computer science fundamentals, blockchain theory, smart contract coding, DApp front‑end, and security auditing.
- Primary programming languages are Solidity (≈90% of contracts) and Rust (gaining traction for high‑performance chains).
- Understanding consensus (PoW, PoS, DPoS, PoH) and tokenomics is vital for protocol design.
- Smart contract security is critical, with total DeFi hacks (2021‑2024) highlighting the risk.
- Market demand is soaring (942 B by 2032) and salaries range from 500k+ senior roles.
Learn Python in 30 Days
Python is one of the most versatile and in-demand programming languages in the world. Created by Guido van Rossum and first released on February 20, 1991, Python has grown from a hobby project to the 1 programming language on the TIOBE Index as of 2024 . With over 18.2 million active developers worl
CSS Flexbox Cheat Sheet: The Complete Reference Guide
CSS Flexbox is a one‑dimensional layout model that uses a main axis (set by flex-direction) and a cross axis to control distribution and alignment of flex items within a container.
justify-contentaligns items along the main axis, whilealign-itemsandalign-contentwork on the cross axis (the latter only with wrapped lines).- Container properties (
display,flex-direction,flex-wrap,justify-content,align-items,align-content,gap) manage group distribution; item properties (order,flex-grow,flex-shrink,flex-basis,flex,align-self) control individual behavior. - The
flexshorthand (e.g.,flex: 1,flex: none) combines grow, shrink, and basis; extra space is allocated by and overflow is resolved by . - Common patterns include perfect centering, navbar push‑right via
margin-left:auto, Holy Grail layout, responsive card grids withgap, and sticky footers using column direction. - Beware of pitfalls:
align-contenthas no effect on single‑line containers, and the defaultmin-width:autocan prevent shrinking, requiringmin-width:0to avoid overflow.