python
47 lines · 7 steps
Per-request SQLAlchemy sessions in Flask
A request-scoped database session that opens lazily and commits or rolls back automatically when each request ends.
Explained by
highlit
1from flask import Flask, g, jsonify, request, abort
2from sqlalchemy import create_engine
3from sqlalchemy.orm import scoped_session, sessionmaker
4
5app = Flask(__name__)
6engine = create_engine(app.config.get("DATABASE_URL", "postgresql://localhost/app"), future=True)
7SessionFactory = sessionmaker(bind=engine, autoflush=False, expire_on_commit=False)
8
9
10def get_session():
11 if "db_session" not in g:
12 g.db_session = SessionFactory()
13 return g.db_session
14
15
16@app.teardown_appcontext
17def close_session(exc):
18 session = g.pop("db_session", None)
19 if session is None:
20 return
21 if exc is None:
22 session.commit()
23 else:
24 session.rollback()
25 session.close()
26
27
28@app.post("/users")
29def create_user():
30 payload = request.get_json(silent=True) or {}
31 email = payload.get("email")
32 if not email:
33 abort(422, description="email is required")
34
35 session = get_session()
36 user = User(email=email, name=payload.get("name"))
37 session.add(user)
38 session.flush()
39 return jsonify(id=user.id, email=user.email), 201
40
41
42@app.get("/users/<int:user_id>")
43def show_user(user_id):
44 user = get_session().get(User, user_id)
45 if user is None:
46 abort(404)
47 return jsonify(id=user.id, email=user.email, name=user.name)
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Tying a session to Flask's request-scoped `g` gives each request its own isolated database connection without global state.
- 2Committing or rolling back in `teardown_appcontext` centralizes transaction handling so individual routes never manage it manually.
- 3Lazy creation via a helper means a session is only opened when a route actually touches the database.
Related explainers
python
from flask import Blueprint, jsonify, request, abort v1 = Blueprint("users_v1", __name__) v2 = Blueprint("users_v2", __name__)
Versioning a Flask API with Blueprints
api versioning
blueprints
rest
Intermediate
7 steps
python
import time import threading from enum import Enum from functools import wraps
Building a circuit breaker in Python
circuit-breaker
resilience
decorators
Advanced
7 steps
python
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector from django.core.cache import cache from django.db.models import F from django.http import JsonResponse
Ranked full-text search in Django
full-text-search
debouncing
caching
Advanced
9 steps
python
import os from datetime import timedelta
Class-based config in a Flask app factory
configuration
app-factory
inheritance
Intermediate
7 steps
python
import time from flask import Flask, g, request
Timing requests with Flask hooks
middleware
request-lifecycle
instrumentation
Intermediate
5 steps
javascript
export function diffIds(current, desired) { const currentSet = new Set(current); const desiredSet = new Set(desired);
Diffing sets to sync group membership
set-operations
diffing
transactions
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/per-request-sqlalchemy-sessions-in-flask-explained-python-072a/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.