Skip to content

Commit f3551c8

Browse files
authored
Merge pull request #4036 from greyli/fix-nesting-bp
Fix url_prefix argument for nesting blueprint
2 parents 08e459e + e93704f commit f3551c8

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

CHANGES.rst

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Unreleased
1818
- Show an error when a blueprint name contains a dot. The ``.`` has
1919
special meaning, it is used to separate (nested) blueprint names and
2020
the endpoint name. :issue:`4041`
21+
- Combine URL prefixes when nesting blueprints that were created with
22+
a ``url_prefix`` value. :issue:`4037`
2123

2224

2325
Version 2.0.0

src/flask/blueprints.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def register(self, app: "Flask", options: dict) -> None:
260260
"""Called by :meth:`Flask.register_blueprint` to register all
261261
views and callbacks registered on the blueprint with the
262262
application. Creates a :class:`.BlueprintSetupState` and calls
263-
each :meth:`record` callbackwith it.
263+
each :meth:`record` callback with it.
264264
265265
:param app: The application this blueprint is being registered
266266
with.
@@ -344,13 +344,17 @@ def extend(bp_dict, parent_dict):
344344
app.cli.add_command(self.cli)
345345

346346
for blueprint, bp_options in self._blueprints:
347-
url_prefix = options.get("url_prefix", "")
348-
if "url_prefix" in bp_options:
349-
url_prefix = (
350-
url_prefix.rstrip("/") + "/" + bp_options["url_prefix"].lstrip("/")
347+
bp_options = bp_options.copy()
348+
bp_url_prefix = bp_options.get("url_prefix")
349+
350+
if bp_url_prefix is None:
351+
bp_url_prefix = blueprint.url_prefix
352+
353+
if state.url_prefix is not None and bp_url_prefix is not None:
354+
bp_options["url_prefix"] = (
355+
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
351356
)
352357

353-
bp_options["url_prefix"] = url_prefix
354358
bp_options["name_prefix"] = options.get("name_prefix", "") + self.name + "."
355359
blueprint.register(app, bp_options)
356360

tests/test_blueprints.py

+33
Original file line numberDiff line numberDiff line change
@@ -835,3 +835,36 @@ def grandchild_no():
835835
assert client.get("/parent/no").data == b"Parent no"
836836
assert client.get("/parent/child/no").data == b"Parent no"
837837
assert client.get("/parent/child/grandchild/no").data == b"Grandchild no"
838+
839+
840+
def test_nested_blueprint_url_prefix(app, client):
841+
parent = flask.Blueprint("parent", __name__, url_prefix="/parent")
842+
child = flask.Blueprint("child", __name__, url_prefix="/child")
843+
grandchild = flask.Blueprint("grandchild", __name__, url_prefix="/grandchild")
844+
apple = flask.Blueprint("apple", __name__, url_prefix="/apple")
845+
846+
@parent.route("/")
847+
def parent_index():
848+
return "Parent"
849+
850+
@child.route("/")
851+
def child_index():
852+
return "Child"
853+
854+
@grandchild.route("/")
855+
def grandchild_index():
856+
return "Grandchild"
857+
858+
@apple.route("/")
859+
def apple_index():
860+
return "Apple"
861+
862+
child.register_blueprint(grandchild)
863+
child.register_blueprint(apple, url_prefix="/orange") # test overwrite
864+
parent.register_blueprint(child)
865+
app.register_blueprint(parent)
866+
867+
assert client.get("/parent/").data == b"Parent"
868+
assert client.get("/parent/child/").data == b"Child"
869+
assert client.get("/parent/child/grandchild/").data == b"Grandchild"
870+
assert client.get("/parent/child/orange/").data == b"Apple"

0 commit comments

Comments
 (0)