Skip to content

Commit 836866d

Browse files
authored
Merge pull request pallets#4935 from pgjones/subdomain
Fix subdomain inheritance for nested blueprints
2 parents fa1ee70 + cabda59 commit 836866d

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Version 2.3.0
33

44
Unreleased
55

6+
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
7+
68

79
Version 2.2.3
810
-------------

docs/blueprints.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ name, and child URLs will be prefixed with the parent's URL prefix.
140140
url_for('parent.child.create')
141141
/parent/child/create
142142
143+
In addition a child blueprint's will gain their parent's subdomain,
144+
with their subdomain as prefix if present i.e.
145+
146+
.. code-block:: python
147+
148+
parent = Blueprint('parent', __name__, subdomain='parent')
149+
child = Blueprint('child', __name__, subdomain='child')
150+
parent.register_blueprint(child)
151+
app.register_blueprint(parent)
152+
153+
url_for('parent.child.create', _external=True)
154+
"child.parent.domain.tld"
155+
143156
Blueprint-specific before request functions, etc. registered with the
144157
parent will trigger for the child. If a child does not have an error
145158
handler that can handle a given exception, the parent's will be tried.

src/flask/blueprints.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ def register(self, app: "Flask", options: dict) -> None:
358358
:param options: Keyword arguments forwarded from
359359
:meth:`~Flask.register_blueprint`.
360360
361+
.. versionchanged:: 2.3
362+
Nested blueprints now correctly apply subdomains.
363+
361364
.. versionchanged:: 2.0.1
362365
Nested blueprints are registered with their dotted name.
363366
This allows different blueprints with the same name to be
@@ -453,6 +456,17 @@ def extend(bp_dict, parent_dict):
453456
for blueprint, bp_options in self._blueprints:
454457
bp_options = bp_options.copy()
455458
bp_url_prefix = bp_options.get("url_prefix")
459+
bp_subdomain = bp_options.get("subdomain")
460+
461+
if bp_subdomain is None:
462+
bp_subdomain = blueprint.subdomain
463+
464+
if state.subdomain is not None and bp_subdomain is not None:
465+
bp_options["subdomain"] = bp_subdomain + "." + state.subdomain
466+
elif bp_subdomain is not None:
467+
bp_options["subdomain"] = bp_subdomain
468+
elif state.subdomain is not None:
469+
bp_options["subdomain"] = state.subdomain
456470

457471
if bp_url_prefix is None:
458472
bp_url_prefix = blueprint.url_prefix

tests/test_blueprints.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,55 @@ def index():
950950
assert response.status_code == 200
951951

952952

953+
def test_nesting_subdomains(app, client) -> None:
954+
subdomain = "api"
955+
parent = flask.Blueprint("parent", __name__)
956+
child = flask.Blueprint("child", __name__)
957+
958+
@child.route("/child/")
959+
def index():
960+
return "child"
961+
962+
parent.register_blueprint(child)
963+
app.register_blueprint(parent, subdomain=subdomain)
964+
965+
client.allow_subdomain_redirects = True
966+
967+
domain_name = "domain.tld"
968+
app.config["SERVER_NAME"] = domain_name
969+
response = client.get("/child/", base_url="http://api." + domain_name)
970+
971+
assert response.status_code == 200
972+
973+
974+
def test_child_and_parent_subdomain(app, client) -> None:
975+
child_subdomain = "api"
976+
parent_subdomain = "parent"
977+
parent = flask.Blueprint("parent", __name__)
978+
child = flask.Blueprint("child", __name__, subdomain=child_subdomain)
979+
980+
@child.route("/")
981+
def index():
982+
return "child"
983+
984+
parent.register_blueprint(child)
985+
app.register_blueprint(parent, subdomain=parent_subdomain)
986+
987+
client.allow_subdomain_redirects = True
988+
989+
domain_name = "domain.tld"
990+
app.config["SERVER_NAME"] = domain_name
991+
response = client.get(
992+
"/", base_url=f"http://{child_subdomain}.{parent_subdomain}.{domain_name}"
993+
)
994+
995+
assert response.status_code == 200
996+
997+
response = client.get("/", base_url=f"http://{parent_subdomain}.{domain_name}")
998+
999+
assert response.status_code == 404
1000+
1001+
9531002
def test_unique_blueprint_names(app, client) -> None:
9541003
bp = flask.Blueprint("bp", __name__)
9551004
bp2 = flask.Blueprint("bp", __name__)

0 commit comments

Comments
 (0)