Nesting Blueprints
Blueprints in this codebase support hierarchical organization through nesting. This allows you to group related functionality into sub-modules while maintaining a clean, structured URL and endpoint namespace.
Hierarchical Registration
The core mechanism for nesting is the Blueprint.register_blueprint method. Instead of registering every blueprint directly on the App, you can register a "child" blueprint on a "parent" blueprint. When the parent is eventually registered on the application, all its nested blueprints are registered recursively.
from flask import Blueprint
parent = Blueprint("parent", __name__)
child = Blueprint("child", __name__)
grandchild = Blueprint("grandchild", __name__)
@grandchild.route("/")
def index():
return "Grandchild"
# Nesting the blueprints
child.register_blueprint(grandchild, url_prefix="/grandchild")
parent.register_blueprint(child, url_prefix="/child")
# Registering the top-level parent on the app
app.register_blueprint(parent, url_prefix="/parent")
In this structure, the grandchild index route will be accessible at /parent/child/grandchild/.
URL Prefix and Subdomain Resolution
Nested blueprints automatically inherit and combine configuration from their parents.
URL Prefixes
URL prefixes are concatenated from the parent down to the child. The implementation in Blueprint.register ensures that slashes are handled correctly when joining prefixes:
# From src/flask/sansio/blueprints.py
if state.url_prefix is not None and bp_url_prefix is not None:
bp_options["url_prefix"] = (
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
)
Subdomains
Subdomains are prepended, meaning the child's subdomain becomes a third-level domain (or deeper) relative to the parent's subdomain.
# Example from tests/test_blueprints.py
parent = Blueprint("parent", __name__)
child = Blueprint("child", __name__, subdomain="api")
parent.register_blueprint(child)
app.register_blueprint(parent, subdomain="v1")
# Resulting subdomain: api.v1.example.test
Endpoint Naming and Namespacing
Endpoints in nested blueprints use a dotted notation that reflects the nesting hierarchy. This is critical for generating URLs with url_for.
If you have a blueprint named child nested inside parent, a route named index in the child blueprint will have the endpoint parent.child.index.
Renaming for Multiple Registrations
You can register the same blueprint multiple times under different names or prefixes. This is useful for reusable components. The name parameter in register_blueprint allows you to override the blueprint's internal name for that specific registration instance.
# Example from tests/test_blueprints.py
bp = Blueprint("bp", __name__)
bp2 = Blueprint("bp2", __name__)
@bp.get("/")
def index():
return "Main"
@bp2.get("/")
def sub_index():
return "Sub"
# Register bp2 inside bp with a custom name 'sub'
bp.register_blueprint(bp2, url_prefix="/a", name="sub")
# Register bp twice on the app
app.register_blueprint(bp, url_prefix="/a")
app.register_blueprint(bp, url_prefix="/b", name="alt")
# Resulting endpoints:
# bp.index
# alt.index
# bp.sub.sub_index
# alt.sub.sub_index
Callback Execution Order
When a request matches a route in a nested blueprint, callbacks (like before_request) are executed in order from the application level down to the specific blueprint level.
- Application
before_requestfunctions. - Parent blueprint
before_requestfunctions. - Child blueprint
before_requestfunctions.
Teardown and after-request functions execute in the reverse order. This allows parent blueprints to set up context or security constraints that apply to all nested children.
Constraints and Requirements
- No Self-Nesting: A blueprint cannot be registered on itself. Attempting
bp.register_blueprint(bp)will raise aValueError. - Unique Names: Within a single parent (or the app), every registered blueprint must have a unique name. If you need to register the same blueprint object twice, you must provide a unique
namein the registration options. - Setup Finalization: Once a blueprint has been registered on an application (or another blueprint that is already registered), you can no longer call setup methods like
record,add_url_rule, orbefore_request. Doing so will raise anAssertionError. - Dot Restriction: Blueprint names and endpoint names cannot contain dots (
.), as the dot is reserved as the separator for the hierarchy.