Flask url_for

January 16, 2018

Flask url_for require application and request context to work.

from flask import url_for
url = url_for('page', page_number=2)

Most of the time I will work fine in request routing and rendering, but you might bump into the following error in specific use cases.

Without application context, you will bump into

RuntimeError: Attempted to generate a URL without the application context being pushed. This has to be executed when application context is available.

If application context is not available, you can create an application context.

app = Flask(__name__)

with app.app_context():
    url = url_for('page', page_number=2)

Without request context, you will bump into

RuntimeError: Application was not able to create a URL adapter for request independent URL generation. You might be able to fix this by setting the SERVER_NAME config variable.

If request context is not available, you can create a test request context.

app = Flask(__name__)

with app.test_request_context():
    url = url_for('page', page_number=2)

NOTE: You can use SERVER_NAME configuration to solve this as well, but it will affect the routing as well.

If both application and request context is not available.

app = Flask(__name__)

with app.app_context(), app.test_request_context():
    url = url_for('page', page_number=2)

_external=True parameter

url_for('page', page_number=2) will produce a relative path, e.g. /page/2.

For abosulte path, use url_for('page', page_number=2, _external=True), e.g. https://www.mydomain.com/page/2

If you use app.test_request_context with _external=True, it will always use http://localhost as the domain name. The localhost domain name is hardcoded, since it’s a context for testing.

app = Flask(__name__)

with app.app_context(), app.test_request_context():
    # http://localhost/page/2
    url = url_for('page', page_number=2, _external=True)

You can override the domain with test_request_context’s base_url parameter.

with app.app_context(), app.test_request_context(base_url='https://www.mydomain.com'):
    # https://www.mydomain.com/page/2
    url = url_for('page', page_number=2, _external=True)

You can now create your own url_for function.

def safe_url_for_external(*args, **kwargs):
    with app.app_context(), app.test_request_context(base_url=kwargs['_base_url']):
        del kwargs['_base_url']
        kwargs['_external'] = True
        return url_for(*args, **kwargs)

# https://www.mydomain.com/page/2
url = safe_url_for_external('page', page_number=2, _base_url='https://www.mydomain.com')

NOTE: whenever possible, use the original url_for because it has less overhead, and only use safe_url_for_external in cases where context is not available.

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.