Nested Blueprints in Flask?

UPDATE

Flask 2 was released with support for nested blueprints.

[ START: Part from the docs ]

Nesting Blueprints

It is possible to register a blueprint on another blueprint.

parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)

The child blueprint will gain the parent’s name as a prefix to its name, and child URLs will be prefixed with the parent’s URL prefix.

url_for('parent.child.create')
/parent/child/create

Blueprint-specific before request functions, etc. registered with the parent will trigger for the child. If a child does not have an error handler that can handle a given exception, the parent’s will be tried.

[ END: Part from the docs ]

Source: https://flask.palletsprojects.com/en/2.0.x/blueprints/#nesting-blueprints


OLD ANSWER

My hacky work around is that I made a class called ParentBP that has the following code

from typing import List
from flask import Blueprint

class ParentBP(object):
   name: str
   url_prefix: str
   subdomain: str
   blueprints: List[Blueprint]

def __init__(self, name="", url_prefix="", subdomain="") -> None:
    self.name = name
    self.url_prefix = url_prefix
    self.subdomain = subdomain
    self.blueprints = []

def register_blueprint(self, bp: Blueprint) -> None:
    bp.name = self.name + "-" + bp.name
    bp.url_prefix = self.url_prefix + (bp.url_prefix or "")
    if self.subdomain:
        bp.subdomain = self.subdomain
    self.blueprints.append(bp)

so you can call it similar to a blueprint like below

blueprint1 = Blueprint("blueprint1", __name__)
blueprint2 = Blueprint("blueprint2", __name__, url_prefix="/bp2")

api_v1 = ParentBP("api-v1", url_prefix="/api/v1")
api_v1.register_blueprint(blueprint1)
api_v1.register_blueprint(blueprint)

to make the interface similar to normal registering of blueprints to the flask app, I extended the Flask class as follows

class ExtendedFlask(Flask):

def register_blueprint(self, blueprint: Union[Blueprint, ParentBP], **options: Any) -> None:
    if isinstance(blueprint, ParentBP):
        for bp in blueprint.blueprints:
            super().register_blueprint(bp, **options)
    else:
        return super().register_blueprint(blueprint, **options)

now you can normally do the following

app = ExtendedFlask(__name__)
app.register_blueprint(api_v1)

Leave a Comment