Flask can generate URLs using the url_for()
function of the flask
package. Hardcoding URLs in the templates and view functions is a bad practice. Suppose, we want to re-structure URLs of our blog from /<id>/<post-title>/
to /<id>/post/<post-title>/
. If we had hardcoded URLs in our templates and view functions then we would have to manually visit every template and view function to make the changes. However, with the url_for()
function changes like these could be done in a snap.
The url_for()
function accepts the endpoint and returns the URL as a string. Recall that endpoint refers to the unique name given to URL and most of the time it is the name of the view function. At this point, main2.py
contains a root ( /
) route defined as follows:
1 2 3 4 5 |
#... @app.route('/') def index(): return render_template('index.html', name='Jerry') #... |
To generate root URL call url_for()
as url_for('index')
. The output would be '/'
. The following shell session demonstrates how to use url_for()
inside the console.
1 2 3 4 5 6 7 8 9 |
>>> >>> from main2 import app >>> from flask import url_for >>> >>> with app.test_request_context('/api'): # /api is arbitrarily chosen ... url_for('index') ... '/' >>> |
Notice that we are first creating a request context (and thus application context implicitly). Trying to use url_for()
inside the console without the request context will result in an error. You can learn more about application and request context here.
If url_for()
couldn’t create URL, it will throw BuildError
exception.
1 2 3 4 5 6 7 8 9 |
>>> >>> with app.test_request_context('/api'): ... url_for('/api') ... Traceback (most recent call last): ... werkzeug.routing.BuildError: Could not build url for endpoint '/api Did you mean 'static' instead? >>> |
To generate the absolute URLs pass _external=True
to the url_for()
as follows:
1 2 3 4 5 6 |
>>> >>> with app.test_request_context('/api'): ... url_for('index', _external=True) ... 'http://localhost:5000/' >>> |
Rather than hardcoding URLs in the redirect()
function you should always use url_for()
to generate URLs. For example:
1 2 3 4 5 |
@app.route('/admin/') def admin(): if not loggedin: return redirect(url_for('login')) # if not logged in then redirect the user to the login page return render_template('admin.html') |
To generate URLs for dynamic routes pass dynamic parts as keyword arguments. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> >>> with app.test_request_context('/api'): ... url_for('user_profile', user_id = 100) ... '/user/100/' >>> >>> >>> with app.test_request_context('/api'): ... url_for('books', genre='biography') ... '/books/biography/' >>> >>> |
The extra number of keywords arguments passed to the url_for()
function will be appended to the URL as a query string.
1 2 3 4 5 6 |
>>> >>> with app.test_request_context('/api'): ... url_for('books', genre='biography', page=2, sort_by='date-published') ... '/books/biography/?page=2&sort_by=date-published' >>> |
The url_for()
is one of those few functions which are available to you inside the template. To generate URLs inside templates simply call url_for()
inside the double curly braces {{ ... }}
, as follows:
1 |
<a href="{{ url_for('books', genre='biography') }}">Books</a> |
Output:
1 |
<a href="/books/biography/">Books</a> |
I had a really long comment about how I got lost in this section [Creating URLs in Flask], but after reading a few pages ahead, then back again, I finally realized that only the connecting terminology was missing [for a first time flask user].
I would rephrase:
Recall that endpoint refers to the unique name given to URL and most of the time it is the name of the view function.
as:
Recall that the URL is an app.route() definition (aka view) and an endpoint is defined by the uniquely named def statement immediately following.
werkzeug.routing.BuildError: Could not build url for endpoint ‘/api
Did you mean ‘static’ instead?
@app.route(‘/’)
def index():
@ like this, function test1 not define @app.route()
print(‘url_for(‘test1′)’)
return (‘int’)
def test1():
return(‘test1’)