GET
, POST
и т. д.) при вызове URL-адреса;Фреймворк Flask предоставляет три способа определить правила для системы URL маршрутизации сайта:
blueprint
: @flask.Flask.route()
.blueprint
: flask.Flask.add_url_rule()
.Werkzeug
, которая представлена как flask.Flask.url_map()
.Переменные части маршрута указываются в угловых скобках /<user>/<username>
. По умолчанию переменная часть в URL-адресе принимает любую строку без косой черты /
. Можно указать другой конвертер, используя схему: <converter:name>
, где converter
- это один из конвертеров (указанных ниже), а - name
- имя переменной части маршрута.
Переменные части маршрута name
передаются в функцию-представление, как ключевые аргументы, которая в свою очередь возвращает ответ сервера.
Во Flask доступны следующие конвертеры (преобразователи):
string
: принимает любой текст без косой черты (по умолчанию);int
: принимает целые числа;float
: как int
, но для значений с плавающей запятой;path
: принимает любой текст, но также принимает косые черты;any
: соответствует одному из предоставленных элементов;uuid
: принимает строки UUID
.@app.route()
:@app.route('/') def index(): pass @app.route('/<username>') def show_user(username): pass @app.route('/post/<int:post_id>', methods=['GET', 'POST') def show_post(post_id): pass
app.add_url_rule()
:Метод app.add_url_rule()
регистрирует правило для маршрутизации входящих запросов и построения URL-адресов. Декоратор @app.route()
- это ссылка для вызова метода app.add_url_rule()
с аргументом view_func
.
def index(): pass def show_user(username): pass def show_post(post_id): pass app.add_url_rule('/', view_func=index) app.add_url_rule('/<username>', view_func=show_user, methods=['GET', 'POST') app.add_url_rule('/post/<int:post_id>', view_func=show_post)
Важная деталь, о которой следует помнить, - это то, как Flask обрабатывает завершающие косые черты. Идея состоит в том, чтобы каждый URL оставался уникальным:
404 not found
.Это соответствует тому, как веб-серверы работают со статическими файлами. Это также позволяет безопасно использовать относительные цели ссылок.
Можно определить несколько URL-маршрутов для одной и той же функции-представления, при этом маршруты должны быть уникальными. Также можно указать значения по умолчанию для переменных значений маршрутов.
Пример:
@app.route('/users/', defaults={'page': 1}) @app.route('/users/page/<int:page>') def show_users(page): pass
Код указывает, что маршрут /users/
будет URL-адресом для первой страницы, а /users/page/N
будет URL-адресом для страницы N
.
Если URL-адрес содержит значение по умолчанию, то он будет перенаправлен в более простую форму с редиректом 301. В приведенном выше примере /users/page/1
будет перенаправлен на URL-адрес /users/
. Если маршрут обрабатывает запросы GET
и POST
, убедитесь, что маршрут по умолчанию обрабатывает только GET
запросы, так как при редиректах невозможно сохранить данные формы.
@app.route('/region/', defaults={'id': 1}) @app.route('/region/<int:id>', methods=['GET', 'POST']) def region(id): pass
GET
, POST
и т. д.) при обращении к URL-адресу.Веб-приложения могут использовать разные HTTP-методы при доступе к URL-адресу. По умолчанию маршрут URL-адреса во Flask отвечает только на GET-запросы (их можно не указывать). Для обработки URL-адреса другим методом или несколькими HTTP-методами необходимо использовать аргумент methods
в декораторе экземпляра веб-приложения @app.route()
или метода app.add_url_rule()
.
from flask import request @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': # обработать форму do_the_login() else: # отобразить форму show_the_login_form()
Если присутствует HTTP-метод GET
, то Flask автоматически добавляет поддержку HTTP-метода HEAD
и обрабатывает запросы HEAD
в соответствии с HTTP RFC. Аналогичным образом, автоматически реализуется HTTP-метод OPTIONS
, при наличии POST
.
С версии Flask 2.x, доступны декораторы-помощники, в которых одноименный метод обращения к маршруту уже подставлен:
@app.delete()
- ссылка для app.route()
с подставленным аргументом methods=['DELETE']
;@app.get()
- ссылка для app.route()
с подставленным аргументом methods=['GET']
;@app.patch()
- ссылка для app.route()
с подставленным аргументом methods=['PATCH']
;@app.post()
- ссылка для app.route()
с подставленным аргументом methods=['POST']
;@app.put()
- ссылка для app.route()
с подставленным аргументом methods=['PUT']
;Пример использования:
@app.post('/login') def index(): pass # эквивалентен @app.route('/login', methods=['POST']) def index(): pass
Для создания собственного конвертора маршрута необходимо наследоваться от класса базового конвертора werkzeug.routing.BaseConverter
, а для его регистрации или изменения уже имеющихся конвертеров, можно использовать метод экземпляра приложения app.url_map()
Изменение или регистрация нового конвертера маршрутизации осуществляется после создания класса конвертера, но до подключения каких-либо маршрутов.
Конвертер на основе регулярных выражений должен иметь атрибут regex
с соответствующим регулярным выражением. Если конвертер может принимать аргументы в правиле URL-адреса, он должен принимать их в своем методе __init__
.
Пример конвертера на основе регулярных выражений:
from flask import Flask from werkzeug.routing import BaseConverter # создаем экземпляр веб-приложения app = Flask(__name__) # определяем класс конвертера регулярных выражений class RegexConverter(BaseConverter): def __init__(self, url_map, *items): super(RegexConverter, self).__init__(url_map) self.regex = items[0] # регистрируем конвертер # правила использования: `<regex():name>` app.url_map.converters['regex'] = RegexConverter # определяем маршрут на основе регулярного выражения @app.route('/<regex('[abcABC0-9]{4,6}'):uid>-<slug>/') def example(uid, slug): return f'uid: {uid}, slug: {slug}'
Теперь URL-адрес http://localhost:5000/abc9-foo/
возвратит код ответа 200, а функция-представление example()
- строку 'uid: abc9, slug: foo'
. URL-адрес http://localhost:5000/abcd-foo/
будет неправильным и станет генерировать ошибку 404:
Класс пользовательского конвертера может реализовать метод .to_python()
для преобразования согласованной строки в какой-либо другой объект, что также может выполнить дополнительную проверку, которая была невозможна с атрибутом regex
, и в этом случае должна вызвать ошибку werkzeug.routing.ValidationError
. Возникновение любых других ошибок приведет к ошибке 500.
Конвертер может реализовать метод .to_url()
для преобразования объекта Python в строку при построении URL-адреса. Любая возникшая здесь ошибка будет преобразована в ошибку werkzeug.routing.BuildError
и в конечном итоге вызовет ошибку 500.
В этом примере реализуется BooleanConverter
, который будет соответствовать строкам , 'yes
', 'no
', и 'maybe
', возвращая случайное значение False
или True
для URL с 'maybe
'.
from flask import Flask from werkzeug.routing import BaseConverter, ValidationError from random import randrange # создаем экземпляр веб-приложения app = Flask(__name__) # определяем класс конвертера class BooleanConverter(BaseConverter): regex = r"(?:yes|no|maybe)" def __init__(self, url_map, maybe=False): super().__init__(url_map) self.maybe = maybe def to_python(self, value): # если прилетает `maybe` if value == "maybe": if self.maybe: # генерируем случайный `False` или `True` return bool(randrange(2)) raise ValidationError # если `value` будет равно 'yes', то возвращается # `True`, если 'no' - то `False` return value == 'yes' # регистрируем конвертер # правила использования: `<bool():name>` app.url_map.converters['bool'] = BooleanConverter # маршрут только для `/yes` или `/no` ## Поддержка субдоиенов в URL-маршрутах.('/<bool:rocks>') def vote(rocks): return f'vote: {rocks}' # выражение `bool(maybe=True)` к маршрутам `/talk/yes` # и `/talk/no` дополнительно включает поддержку `/talk/maybe` @app.route('/talk/<bool(maybe=True):foo>') def talk(foo): return f'talk: {foo}' if __name__ == '__main__': app.run(debug=True, port=5000)
Декоратор экземпляра приложения @app.route()
и его метод app.add_url_rule()
принимает аргумент поддомена subdomain
, сопоставления маршрута с поддоменом. Экземпляр схемы blueprint
также принимает этот аргумент, чтобы установить соответствие поддомена для всех маршрутов в определенной схеме blueprint
.
Для успешного обслуживания доменов необходимо установить базовый домен в конфигурации веб-приложения app.config['SERVER_NAME']
, чтобы Flask знал, с чем сопоставлять. Также нужно будет указать порт, если только приложение не работает на порту 80 или 443 (т. е. в рабочей среде).
Начиная с Flask 1.0, также необходимо установить аргумент subdomain_matching=True
при создании объекта приложения.
from flask import Flask app = Flask(__name__, subdomain_matching=True) app.config['SERVER_NAME'] = "example.com:5000" @app.route("/") def index(): return "example.com" @app.route("/", subdomain="<subdomain>") def sub_index(subdomain): return f'{subdomain}.example.com'
Пример для приложения со схемами Blueprint
:
egg = Blueprint("egg", __name__, subdomain="egg") @egg.route("/") def index(): return "egg.example.com"
При локальном запуске необходимо отредактировать файл hosts
на компьютере (/etc/hosts
в Unix), чтобы он знал, как маршрутизировать поддомены, т. к. домены локально не существуют.
# добавьте строку в файл `hosts` 127.0.0.1 localhost example.com egg.example.com
Не забудьте указать порт в браузере: http://example.com:5000
, http://egg.example.com:5000
и т. д.
При развертывании приложения на боевом сервере, необходимо настроить DNS и прокси-сервер (например Nginx) для маршрутизации всех поддоменов веб-приложения.
Помните, что все маршруты Flask на самом деле являются экземплярами werkzeug.routing.Rule
. Обращение к документации Werkzeug для Rule покажет вам довольно много вещей, которые могут делать маршруты, которые не учитываются в документации Flask, т.к. они хорошо документированы в werkzeug
.