Динамические URL и конвертеры
URL может содержать переменные части: /user/42, /post/hello-world. Flask вытаскивает их из пути и передаёт в view-функцию как аргументы.
Динамический маршрут — это шаблон с «дыркой»: /user/<int:user_id>. Любой подходящий путь матчится, а значение из дырки приезжает в функцию параметром. Конвертер задаёт тип и форму этой дырки.
Жёстко прописывать каждый URL невозможно — пользователей миллионы. Нужен шаблон: «после /user/ идёт число — это id». Flask описывает переменную часть в угловых скобках, а имя внутри становится именем параметра функции.
@app.route("/user/<int:user_id>")
def show_user(user_id):
return f"Пользователь №{user_id}"
@app.route("/post/<slug>")
def show_post(slug):
return f"Статья: {slug}"
Конвертер перед двоеточием задаёт тип. Основные: string (по умолчанию, без слэшей), int (целое), float, path (строка со слэшами), uuid. Конвертер не просто кастует тип — он ещё фильтрует: <int:id> не совпадёт с /user/abc, и Flask вернёт 404, не дойдя до функции. Это бесплатная валидация на уровне маршрута.
@app.route("/files/<path:filepath>") # ловит и docs/intro.txt
def serve(filepath):
return f"Файл: {filepath}"
Конвертеры — это маленькая, но недооценённая защита. Они не просто кастуют тип: они отсекают мусорные запросы ещё до твоего кода, экономя обработку и устраняя целый класс ошибок «а вдруг там не число». Выбирая между голым id и человекочитаемым slug, думай о SEO и пользователе: /post/42 ничего не говорит, /post/kak-rabotaet-flask и читается, и лучше индексируется. Часто используют гибрид — и slug, и id в URL. И ещё нюанс: порядок объявления маршрутов имеет значение, когда шаблоны могут пересекаться; более общий path-маршрут способен «перехватить» запросы, предназначенные конкретным путям, поэтому располагай специфичные правила раньше широких.
Как работает под капотом
Каждое правило компилируется в регулярное выражение. Конвертер int даёт паттерн вроде \d+, string — «всё кроме слэша». При запросе Werkzeug прогоняет путь через эти регулярки, и первое совпавшее правило выигрывает; захваченные группы становятся аргументами функции.
/user/42
│
▼
правило "/user/<int:user_id>"
компилируется в ^/user/(\d+)$
│ совпало, группа = "42"
▼
конвертер int: "42" → 42 (тип int)
│
▼
show_user(user_id=42)
Если бы пришло /user/abc, регулярка \d+ не совпала бы — Flask вернул бы 404 ещё до вызова функции. Смоделируем эту проверку и приведение типа вручную.
import re
def match_route(pattern_regex, converter, path):
m = re.match(pattern_regex, path)
if not m:
return ("404", None)
raw = m.group(1)
value = converter(raw)
return ("200", value)
# имитируем правило /user/<int:user_id>
rx = r"^/user/(\d+)$"
for p in ["/user/42", "/user/abc", "/user/7"]:
status, val = match_route(rx, int, p)
print(p, "->", status, val, type(val).__name__ if val is not None else "")
Запусти: /user/abc отсеивается как 404, а число приезжает уже типом int. Точно так конвертеры работают внутри Flask.
Частые ошибки
- Имя в URL не совпадает с параметром функции.
<user_id>иdef show(id)— ошибка. Имена должны совпадать буква в букву. - Ждать int, а получать string. Без конвертера значение приходит строкой; сравнение с числом даст сюрприз.
- Использовать path там, где не надо. path ловит слэши и может «съесть» соседние маршруты.
Best practices
- Ставь конвертер типа — это валидация и защита от мусорных URL бесплатно.
- Для «человекочитаемых» URL используй slug (string), а не голый id, где это уместно для SEO.
- Имена переменных делай осмысленными: user_id, а не x.
Что запомнить
- Переменные части URL пишут в угловых скобках: /user/<int:id>.
- Конвертер задаёт тип (int, string, path, uuid) и отфильтровывает неподходящие пути.
- Имя в URL должно совпадать с именем параметра функции.
- Для SEO предпочитай человекочитаемые slug вместо голых id.
Итог: динамические маршруты — это шаблоны с переменными частями в угловых скобках. Конвертер задаёт тип и заодно отфильтровывает неподходящие пути. Значение приезжает в функцию готовым аргументом нужного типа.