#8 Создание URL во Flask

Flask может генерировать URL с помощью функции url_for() из пакета flask. URL можно задавать вручную в шаблонах и функциях представления, но это не очень хорошая практика. Предположим, возникла необходимость поменять структуру ссылок для блога с /<id>/<post-title>/ на /<id>/post/<post-title>/ . Если URL были заданы вручную в шаблонах и функциях, тогда придется вручную редактировать их во всех местах. Функция url_for() позволяет произвести то же изменение одним щелчком.

Функция url_for() принимает конечную точку и возвращает URL в виде строки. Стоит напомнить, что конечная точка ссылается на уникальное имя URL и в большинстве случае — это имя функции представления. Например, сейчас main2.py имеет определенный корневой путь(/):

#...
@app.route('/')
def index():
    return render_template('index.html', name='Jerry')
#...

Чтобы сгенерировать корневой URL, нужно вызвать url_for() следующим образом: url_for(‘index’). Выводом будет '/'. Следующий код демонстрирует, как использовать url_for() в консоли.

>>> from main2 import app
>>> from flask import url_for
>>>
>>> with app.test_request_context('/api'): # путь /api выбран произвольно
...     url_for('index')
...
'/'
>>>

Стоит обратить внимание, что сперва создается контекст запроса (и таким образом — контекст приложения). Если попробовать использовать url_for() внутри консоли без вызова контекста, выйдет ошибка. Больше о контекстах запросов и приложения можно прочитать здесь.

Если url_for() не может создать URL, она вызовет исключение BuildError.

>>>
>>> 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?
>>>

Чтобы сгенерировать абсолютной URL, нужно передать функции url_for() аргумент external=True:

>>>
>>> with app.test_request_context('/api'):
...     url_for('index', _external=True)
...
'https://localhost:5000/'
>>>

Вместо того чтобы прописывать URL в функции redirect(), стоит всегда использовать url_for() для этого. Например:

@app.route('/admin/')
def admin():
    if not loggedin:
        return redirect(url_for('login')) # если не залогинен, выполнять редирект на страницу входа
    return render_template('admin.html')

Чтобы сгенерировать URL для динамических адресов, нужно передать динамические части в виде аргументов-ключевых слов. Например:

>>>
>>> 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/'
>>>

Дополнительные аргументы-ключевые слова, переданные функции url_for(), будут добавлены к URL в виде строки запроса.

>>>
>>> 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'
>>>

url_for() — одна из тех функций, которую можно использовать внутри шаблона. Чтобы сгенерировать URL внутри шаблонов, нужно просто вызвать url_for() внутри фигурных скобок {{ … }}:

<a href="{{ url_for('books', genre='biography') }}">Books</a>

Вывод:

<a href="/books/biography/">Books</a>