pythonflaskjinja2

How to build external URL with parameters in flask/jinja2?


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.


Edit

I currently use urlencode filter to build parameters:

<a href="https://example.net/?{{ dict(foo='bar') | urlencode }}">external link</a>

Solution

  • 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"))