Tutorial: Managing Resources with g
In this tutorial, you will build a resource management system for a Flask application. You will learn how to use the g object to store and reuse resources like database connections during a single request, and how to ensure those resources are properly cleaned up using teardown functions.
Prerequisites
To follow this tutorial, you should have a basic Flask application structure. This example uses sqlite3 for the database.
Step 1: Lazy-Loading a Database Connection
The g object is an instance of _AppCtxGlobals. It serves as a namespace for storing data during an application context. A common pattern is to store a database connection in g so that multiple functions can access the same connection without creating new ones.
Create a file named db.py and implement a get_db function:
import sqlite3
from flask import current_app, g
def get_db():
"""Connect to the application's configured database. The connection
is unique for each request and will be reused if this is called
again.
"""
if "db" not in g:
g.db = sqlite3.connect(
current_app.config["DATABASE"],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
In this step, you check if "db" is already present in g using the in operator (implemented by _AppCtxGlobals.__contains__). If it isn't, you create the connection and assign it to g.db. Subsequent calls to get_db within the same request will return the existing connection.
Step 2: Implementing Automatic Teardown
Resources stored in g must be closed when the request ends. The AppContext class manages this lifecycle. When a context is popped, it triggers functions registered with teardown_appcontext.
Add a close_db function to db.py and a registration function:
def close_db(e=None):
"""If this request connected to the database, close the
connection.
"""
db = g.pop("db", None)
if db is not None:
db.close()
def init_app(app):
"""Register database functions with the Flask app."""
app.teardown_appcontext(close_db)
The g.pop() method (from _AppCtxGlobals.pop) safely removes the attribute if it exists. By calling app.teardown_appcontext(close_db), you tell Flask to call close_db every time the application context is destroyed, even if an unhandled exception occurred.
Step 3: Storing Request-Specific State
You can also use g to store information about the current user or other request-specific state. This is typically done in a before_request hook.
In your authentication module (e.g., auth.py), you can load the user:
from flask import Blueprint, g, session
from .db import get_db
bp = Blueprint("auth", __name__)
@bp.before_app_request
def load_logged_in_user():
"""If a user id is stored in the session, load the user object
from the database into g.user.
"""
user_id = session.get("user_id")
if user_id is None:
g.user = None
else:
g.user = (
get_db().execute("SELECT * FROM user WHERE id = ?", (user_id,)).fetchone()
)
By assigning the user to g.user, it becomes available to all other view functions and templates during the rest of the request.
Step 4: Accessing g in Tests and CLI
The g object is only accessible when an AppContext is active. If you try to access it outside of a request or a CLI command, Flask will raise a RuntimeError. In tests or scripts, you must manually push a context.
def test_db_connection(app):
with app.app_context():
# Now g is available
db = get_db()
assert "db" in g
# After the 'with' block, the context is popped and close_db is called
When the with app.app_context(): block exits, the AppContext.pop() method is called, which executes your close_db function and clears the g namespace.
Summary
By the end of this tutorial, you have implemented:
- Lazy-loading: Using
gto create a database connection only when needed. - Resource Reuse: Accessing the same
g.dbinstance throughout a request. - Safe Cleanup: Using
teardown_appcontextto ensure connections are closed. - Global State: Using
g.userto share the current user across your application.
For next steps, consider exploring how AppContext handles nested pushes or how to use g.setdefault() to initialize complex objects safely.