Storing Data with the g Proxy
To store data that persists for the duration of a single application context (such as a request or a CLI command), use the g proxy. This object is an instance of _AppCtxGlobals and serves as a temporary namespace for request-bound data.
from flask import g
@app.route("/user/<name>")
def profile(name):
# Store data on g
g.user_name = name
return f"Hello, {g.user_name}!"
Managing Data with Dict-like Methods
The g proxy (via _AppCtxGlobals) supports standard attribute access as well as several dictionary-like methods for safer data management.
- Check for existence: Use the
inoperator. - Safe retrieval: Use
g.get(name, default). - Removal: Use
g.pop(name, default)to retrieve and remove an item. - Default initialization: Use
g.setdefault(name, default)to ensure a value exists.
from flask import g
def check_context():
# Check if 'db' is initialized
if "db" in g:
print("Database connection exists")
# Get a value with a default
theme = g.get("theme", "light")
# Remove and return a value
user = g.pop("user", None)
Pattern: Lazy Loading Resources
A common pattern in this codebase is using g to cache resources like database connections so they are only created once per request. This is demonstrated in the flaskr tutorial's database module.
# examples/tutorial/flaskr/db.py
import sqlite3
from flask import current_app, g
def get_db():
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
def close_db(e=None):
db = g.pop("db", None)
if db is not None:
db.close()
To ensure the resource is cleaned up, register the cleanup function with app.teardown_appcontext:
def init_app(app):
app.teardown_appcontext(close_db)
Pattern: Request Pre-processing
You can use before_app_request hooks to populate g with data that subsequent view functions or templates might need, such as the currently logged-in user.
# examples/tutorial/flaskr/auth.py
from flask import g, session
from .db import get_db
@bp.before_app_request
def load_logged_in_user():
user_id = session.get("user_id")
if user_id is None:
g.user = None
else:
# Store the user object in g for the rest of the request
g.user = (
get_db().execute("SELECT * FROM user WHERE id = ?", (user_id,)).fetchone()
)
Accessing g in Templates
The g object is automatically available in Jinja2 templates via the default template context processor in src/flask/templating.py.
<!-- examples/tutorial/flaskr/templates/base.html -->
<nav>
<ul>
{% if g.user %}
<li><span>{{ g.user['username'] }}</span></li>
<li><a href="{{ url_for('auth.logout') }}">Log Out</a></li>
{% else %}
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
<li><a href="{{ url_for('auth.login') }}">Log In</a></li>
{% endif %}
</ul>
</nav>
Troubleshooting
- RuntimeError: Working outside of application context: This occurs if you try to access
gwhen no application context is active. Ensure you are within a request or usewith app.app_context():in scripts or tests. - Data Persistence: Data stored in
gis lost as soon as the application context ends (usually at the end of the request). It does not persist between different requests. Usesessionfor data that needs to persist across multiple requests. - Attribute Errors: Accessing a non-existent attribute on
graises anAttributeError. Useg.get("attr_name")if you are unsure if the attribute has been set.