Introduction to Blueprints
Blueprints in this codebase provide a way to organize related views, templates, and static files into modular components. Instead of registering routes directly on a central application object, you define them on a Blueprint instance. This decouples the definition of your application's structure from the actual application creation, enabling cleaner code organization and reusability.
The Blueprint class (found in src/flask/sansio/blueprints.py) inherits from Scaffold, which provides the standard decorators for routing and request lifecycle management.
Core Concepts
Deferred Registration
Unlike the main application object, a Blueprint does not immediately register routes or handlers. Instead, it records these actions as "deferred functions." When you call a decorator like @bp.route, the blueprint stores a lambda or function in its deferred_functions list.
These functions are only executed when the blueprint is formally registered on an application via app.register_blueprint(). This process uses a BlueprintSetupState object to apply the recorded settings to the real application instance.
Namespacing
One of the primary roles of a blueprint is to provide namespacing for endpoints. When a blueprint is registered, its name is prepended to all its endpoints. For example, a view named login in a blueprint named auth becomes accessible via the endpoint auth.login.
Defining and Registering Blueprints
A typical blueprint definition involves specifying a name and an import_name (usually __name__). You can also provide a url_prefix to group all routes under a specific path.
In examples/tutorial/flaskr/auth.py, the authentication module is defined as follows:
from flask import Blueprint, render_template, request, session, url_for, redirect
# Define the blueprint
bp = Blueprint("auth", __name__, url_prefix="/auth")
@bp.route("/login", methods=("GET", "POST"))
def login():
if request.method == "POST":
# ... login logic ...
return redirect(url_for("index"))
return render_template("auth/login.html")
To make these routes active, the blueprint must be registered in the application factory (typically in __init__.py):
def create_app():
app = Flask(__name__)
# ...
from . import auth
app.register_blueprint(auth.bp)
return app
Resource Management
Blueprints can manage their own templates and static files, keeping them isolated from the rest of the application.
- Templates: Specified via the
template_folderargument. Note that blueprint templates have lower precedence than the application's globaltemplatesfolder. - Static Files: Specified via
static_folder. If aurl_prefixis used, the static files are served from{url_prefix}/{static_url_path}.
Advanced Blueprint Features
Blueprint-Specific Error Handlers
You can define error handlers that only trigger for requests handled by a specific blueprint. This is useful for returning module-specific error pages or JSON responses.
As seen in tests/test_blueprints.py:
frontend = Blueprint("frontend", __name__)
@frontend.errorhandler(403)
def frontend_forbidden(e):
return "frontend says no", 403
@frontend.route("/frontend-no")
def frontend_no():
abort(403)
Application-Wide Hooks
Blueprints also provide methods to register hooks that affect the entire application, not just the blueprint's routes. These methods are prefixed with app_:
before_app_request: Runs before every request to the application.app_errorhandler: Registers a global error handler.app_template_filter: Registers a Jinja filter available in all templates.
Nested Blueprints
Blueprints can be registered on other blueprints using the register_blueprint method. This allows for hierarchical organization of complex applications. When nesting, the url_prefix and subdomain settings are concatenated.
parent = Blueprint("parent", __name__, url_prefix="/parent")
child = Blueprint("child", __name__, url_prefix="/child")
parent.register_blueprint(child)
# Child routes will now be prefixed with /parent/child
Constraints and Requirements
- Immutability After Registration: Once a blueprint has been registered on an application, it cannot be modified. Calling setup methods like
route()orbefore_request()after registration will raise anAssertionError. - Naming Restrictions: The
nameof a blueprint cannot contain a dot (.), as dots are used to separate the blueprint name from the endpoint name inurl_for. - Unique Names: Each blueprint must have a unique name within an application. If you need to register the same blueprint multiple times, you must provide a unique
nameduring registration using thenameparameter inregister_blueprint.