Python Flask Cheat Sheet
Covers Flask app setup, routing, request and response handling, Jinja2 templates, and organizing routes with blueprints.
Minimal Flask App
The smallest possible Flask application.
from flask import Flaskapp = Flask(__name__)@app.route("/")def index(): return "Hello, Flask!"if __name__ == "__main__": app.run(debug=True) # Dev server with auto-reload# Run with: flask --app app run --debug# or: python app.py
Routes & Request Handling
Read query strings, JSON bodies, and path parameters.
from flask import request, jsonify@app.route("/users/<int:user_id>")def get_user(user_id): return jsonify({"id": user_id})@app.route("/search")def search(): query = request.args.get("q", "") # Query string param return jsonify({"query": query})@app.route("/users", methods=["POST"])def create_user(): data = request.get_json() # Parse JSON body name = data.get("name") return jsonify({"created": name}), 201
Templates (Jinja2)
Render server-side HTML with Jinja2.
from flask import render_template@app.route("/profile/<username>")def profile(username): return render_template("profile.html", username=username)# templates/profile.html# <h1>Hello, {{ username }}!</h1># {% if username == "admin" %}<p>Welcome back</p>{% endif %}# {% for item in items %}<li>{{ item }}</li>{% endfor %}
Blueprints
Organize routes into reusable modules.
# blog/routes.pyfrom flask import Blueprintbp = Blueprint("blog", __name__, url_prefix="/blog")@bp.route("/")def index(): return "Blog home"# app.pyfrom blog.routes import bpapp.register_blueprint(bp)
Flask Essentials
Frequently used objects and helpers.
- app.config- Dict-like object for app configuration (e.g. SECRET_KEY, DEBUG)
- request.form- Access form-encoded POST data
- request.args- Access URL query string parameters
- abort(404)- Short-circuit a view with an HTTP error response
- url_for('view_name')- Build a URL by endpoint name instead of hardcoding paths
- flash('message')- Queue a one-time message to show on the next rendered page
- g- Application context object for storing per-request data
Application Factory & Extensions
Avoid global app state so you can create multiple configured instances (testing, prod) cleanly.
from flask import Flaskfrom flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()def create_app(config_object="config.ProductionConfig"): app = Flask(__name__) app.config.from_object(config_object) db.init_app(app) from .blog.routes import bp as blog_bp app.register_blueprint(blog_bp) return app# wsgi.py# from myapp import create_app# app = create_app()## Testing: app = create_app("config.TestConfig")
Application/Request Context & Hooks
Run code around every request and understand when Flask's context globals are valid.
from flask import g, requestimport time@app.before_requestdef start_timer(): g.start = time.monotonic()@app.after_requestdef log_duration(response): elapsed_ms = (time.monotonic() - g.start) * 1000 app.logger.info("%s %s took %.1fms", request.method, request.path, elapsed_ms) return response@app.teardown_appcontextdef close_db(exception=None): db_conn = g.pop("db_conn", None) if db_conn is not None: db_conn.close()# request/g are only valid DURING an active request/app context —# accessing them from a background thread raises RuntimeError.
Custom Error Handlers & JSON APIs
Turn exceptions into consistent, structured error responses instead of default HTML pages.
from flask import jsonifyfrom werkzeug.exceptions import HTTPExceptionclass APIError(Exception): def __init__(self, message, status_code=400): super().__init__(message) self.message = message self.status_code = status_code@app.errorhandler(APIError)def handle_api_error(err): return jsonify({"error": err.message}), err.status_code@app.errorhandler(HTTPException)def handle_http_error(err): return jsonify({"error": err.name, "description": err.description}), err.code@app.errorhandler(500)def handle_unexpected(err): app.logger.exception("Unhandled error") return jsonify({"error": "internal_server_error"}), 500
Testing with the Test Client & Custom CLI Commands
Exercise routes without a running server and script maintenance tasks via 'flask' commands.
# test_app.pydef test_create_user(client): resp = client.post("/users", json={"name": "Ada"}) assert resp.status_code == 201 assert resp.get_json()["created"] == "Ada"# conftest.pyimport pytestfrom myapp import create_app@pytest.fixturedef client(): app = create_app("config.TestConfig") with app.test_client() as c: yield c# Custom CLI command@app.cli.command("seed-db")def seed_db(): """flask seed-db -- populate initial data.""" db.session.add_all([...]) db.session.commit() print("Seeded.")
Advanced Flask Concepts
Patterns that come up once an app grows past a single-file prototype.
- async def view- Flask supports 'async def' route handlers directly (via ASGI-compatible servers); useful for awaiting I/O-bound calls
- Flask-Login- Extension providing session-based user authentication, current_user, and login_required
- Application Context vs Request Context- App context (current_app, g) can outlive a request; request context (request, session) exists only per-request
- before_first_request (removed 2.3+)- Deprecated hook; use app-factory init code or 'with app.app_context():' at startup instead
- Flask-Migrate- Wraps Alembic to provide 'flask db migrate/upgrade' commands for SQLAlchemy schema changes
- send_from_directory- Safely serve files from a directory while preventing path-traversal outside it
- SERVER_NAME config- Enables url_for(..., _external=True) to build absolute URLs outside a request context
Never run app.run(debug=True) in production — the interactive debugger can execute arbitrary code from anyone who reaches an error page. Serve with a WSGI server like gunicorn behind a reverse proxy instead.