Global vs. Local Blueprint Hooks
In this project, the Blueprint class provides two levels of hooks: local hooks that only trigger for routes defined within the blueprint, and global hooks that affect every request across the entire application.
Local Blueprint Hooks
To execute logic only for requests handled by a specific blueprint, use the standard request decorators. These are useful for blueprint-specific setup, such as verifying a specific header or modifying the response of a specific module.
from flask import Blueprint
bp = Blueprint("bp", __name__)
@bp.before_request
def before_bp():
# This only runs for routes in 'bp'
pass
@bp.after_request
def after_bp(response):
# This only runs for routes in 'bp'
response.headers["X-Blueprint-Custom"] = "True"
return response
@bp.errorhandler(404)
def handle_local_404(e):
# This only catches 404s raised within 'bp' routes
return "Blueprint resource not found", 404
These hooks are merged into the application's hook dictionaries during registration via _merge_blueprint_funcs in src/flask/sansio/blueprints.py.
Global Application Hooks
To influence the entire application from within a blueprint, use the app_ prefixed decorators. These are functionally equivalent to calling the corresponding methods on the Flask application object itself.
Global Request Processing
A common use case is loading user data for every request in the application, regardless of which blueprint handles it. The following example from examples/tutorial/flaskr/auth.py demonstrates using before_app_request to manage authentication state globally.
from flask import Blueprint, g, session
from flaskr.db import get_db
bp = Blueprint("auth", __name__, url_prefix="/auth")
@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()
)
Global Error Handling
You can centralize error handling for the whole app within a specific blueprint using app_errorhandler. This is useful for creating a dedicated "errors" module.
errors_bp = Blueprint("errors", __name__)
@errors_bp.app_errorhandler(403)
def forbidden_handler(e):
return "you shall not pass", 403
# This handler will now catch 403 errors raised anywhere in the app,
# even in routes defined outside of 'errors_bp'.
Global Template Utilities
Blueprints can also register utilities that become available in all Jinja templates across the application, not just those rendered by the blueprint's views.
bp = Blueprint("utils", __name__)
@bp.app_template_filter("reverse")
def reverse_filter(s):
return s[::-1]
@bp.app_context_processor
def inject_now():
import datetime
return {"now": datetime.datetime.utcnow()}
These methods (like app_template_filter and app_context_processor) use record_once internally to ensure that the utility is only registered with the application once, even if the blueprint is registered multiple times.
Registration Lifecycle and Restrictions
Blueprint hooks are "deferred." When you use a decorator like @bp.before_app_request, the function is added to self.deferred_functions. These functions are only executed when app.register_blueprint(bp) is called.
Gotcha: Modifying Registered Blueprints
Once a blueprint has been registered with an application, you cannot add new hooks or routes to it. Attempting to do so will raise an AssertionError.
# src/flask/sansio/blueprints.py
def _check_setup_finished(self, f_name: str) -> None:
if self._got_registered_once:
raise AssertionError(
f"The setup method '{f_name}' can no longer be called on the blueprint"
f" '{self.name}'. It has already been registered at least once..."
)
Ensure all decorators and setup logic are completed before calling app.register_blueprint().
Precedence and Overlap
- Templates: Blueprint templates have lower precedence than the application's main
templatesfolder. - Static Files: If a blueprint does not have a
url_prefix, the application's static route will take precedence over the blueprint's static files. - Multiple Registrations: If you register the same blueprint multiple times, global hooks (using
app_decorators) are only applied during the first registration due to the use ofrecord_once.