Simple question, how can I build URL with parameters for external websites?
Flask helper url_for
is really handy to build internal links and I was wandering if it could also be used for external links, but it seems that this is not as simple as it sounds.
<a href="{{ url_for('endpoint', foo='bar') }}">internal</a>
<a href="{{ url_for('https://example.net/', foo='bar', _external=true) }}">external (doesn't work)</a>
from flask import Flask, url_for
app = Flask(__name__)
app.config["SERVER_NAME"] = "example.com"
app.config["PREFERRED_URL_SCHEME"] = "https"
with app.app_context():
# Expected: "https://example.net/?foo=bar"
print(url_for("https://example.net/", foo="bar", _external=True))
url_for
has _external
option, but it seems different from what I imagined.
I currently use urlencode filter to build parameters:
<a href="https://example.net/?{{ dict(foo='bar') | urlencode }}">external link</a>
It is possible to add an external url directly within flasks route map with app.add_url_rule("/", endpoint="www.example.com", host="www.example.com", build_only=True)
however this requires host_matching=True
to be set when creating your application object and this could potentially interfere with how the routing works for your internal routes. I would suggest setting up a separate route map for your external routes by using the werkzeug Map and Rule objects directly.
from werkzeug.routing import Map, Rule
class UrlExternal:
def __init__(self):
self.map = Map([Rule('/', host="www.example.com", endpoint="com_root"),
Rule('/api/<int:val>', host="www.example.net" ,endpoint="net_api")],
host_matching=True)
self.adapter = self.map.bind("", url_scheme="https")
def __call__(self, endpoint, **values):
return self.adapter.build(endpoint, values, force_external=True)
url_external = UrlExternal()
print(url_external("com_root", val=8, param="p"))
print(url_external("net_api", val=9, param="q"))