Шаблоны сайта содержат множество внутренних ссылок: от меню до кнопок и форм. До сих пор мы формировали эти ссылки прямо в тех местах, где они нам нужны:
<form action="/users/{{ user['id'] }}" method="post">
<input type="submit" value="Remove">
</form>
Так же ссылки строятся и в обработчиках, например, при редиректах:
@app.post('/users')
def users_post():
repo = UserRepository()
user = request.form.to_dict()
errors = validate(user)
... # Остальной код
repo.save(user)
# Тут формируется ссылка
return redirect(f'/users/{user["id"]}', code=302)
В примерах выше формирование ссылки зашито прямо в то место, где она используется. Такой способ формирования ссылок потенциально опасен. Например, маршрут может измениться с /users/{id}
на /u/{id}
. Тогда придется пройтись по всем шаблонам и изменить все ссылки /users/{{ user['id'] }}
на /u/{{ user['id'] }}
.
Если этот маршрут удалить, сайт и приемочные тесты продолжат работать, но ссылки начнут вести на страницы 404. Будет лучше, если страницы с такими ссылками начнут выдавать ошибки. Тогда выявить подобные ссылки станет крайне просто.
Чтобы решить эту задачу, придумали именованные маршруты. Каждому маршруту фреймворка присваивается имя, которое затем можно использовать при построении конкретной ссылки. во Flask в качестве такого имени используется имя обработчика:
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/users/')
def users_index():
# Код обработчика
@app.route('/users/<id>')
def users_show(id):
# Код обработчика
@app.route('/')
def index():
# В функцию передается имя обработчика, а она возвращает url
url_for('users_index') # /users/
url_for('users_show', id=3) # /users/3
# Остальной код
В реальных приложениях ссылки формируются во многих их частях:
- В шаблонах
- В обработчиках (при редиректах)
- В письмах
Поэтому большинство фреймворков предоставляют готовую функцию, которую можно использовать везде, где формируются ссылки. В шаблонах Jinja2 ссылки строятся так:
<h1>User List</h1>
<ul>
{% for user in users %}
<li><a href="{{ url_for('users_show', id=user.id) }}">{{ user.name }}</a></li>
{% endfor %}
</ul>
В качестве первого параметра url_for()
передается имя обработчика, а последующими параметрами — необходимые аргументы для функции-обработчика.
Так в шаблоне выше url_for('users_show', id=user.id)
заменится на конкретную ссылку этого обработчика с подставленными плейсхолдерами. Например для пользователя с user.id равным 42 подставится ссылка /users/42
Используйте url_for()
в шаблонах всегда. Так вы сможете избежать проблемы мертвых ссылок, ситуации, когда url обработчика поменяли в коде, но забыли поменять все старые недействительные ссылки в HTML-страницах.
Самостоятельная работа
- Сделайте так, чтобы в обработчиках обращение ко всем маршрутам было через их имена
Эталонное приложение
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.