Hello World во фреймворке Flask
Начать работу с Flask можно с наиболее простого приложения, выводящего "Hello World". Для этого создадим файл main.py и добавим в него следующий код.
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello World' if __name__ == "__main__": app.run()
Это — "Hello World" приложение, реализованное на Flask. Если вы пока не понимаете, как он работает, не переживайте. В последующих разделах каждое действие будет подробно объяснено. Чтобы запустить main.py, воспользуйтесь этой командой в виртуальном окружении Python.
(env) gvido@vm:~/flask_app$ python main.py * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Забегая вперед, выполнение команды запустит локальный сервер для тестирования на порте 5000. Достаточно открыть любой браузер и перейти по адресу http://127.0.0.1:5000/, чтобы увидеть наш "Hello World".
Остановить сервер можно сочетанием клавиш CTRL+C
.
Создание приложения Flask
Каждое приложение Flask представляет собой экземпляр класса, который является WSGI-приложением. WSGI — это интерфейс, обеспечивающий взаимодействие между сервером и вашим Flask-приложением. Чтобы создать экземпляр класса Flask, нужно выполнить следующие шаги:
from flask import Flask app = Flask(__name__)
Первая строка кода осуществляет импорт класса Flask из пакета flask.
Во второй строке создается объект Flask. Конструктор этого класса требует передать ему один обязательный аргумент — название пакета, в большинстве случаев имеет смысл использовать __name__. Это имя позволяет Flask находить статические файлы и шаблоны для вашего приложения.
Создание route (путей)
Маршрутизация — это ключевой элемент Flask, который связывает URL-адреса с функциями-обработчиками запросов. Обычно, чтобы задать маршрут, используется декоратор route. Пример кода:
@app.route('/') def index(): return 'Hello World'
Этот код определяет функцию index()
как обработчик главного URL. Каждый раз, когда приложение получает запрос на этот маршрут, вызывается указанная функция и выполняется ответ.
Можно использовать метод add_url_rule()
для создания маршрутов вместо декоратора route. Хотя add_url_rule()
является простым методом, он предлагает дополнительные возможности, такие как указание конечной точки и функции-обработчика. Обычно совпадение функций-обработчиков с маршрутами выглядит так:
def index(): return 'Hello World' app.add_url_rule('/', 'index', index)
Хотя route чаще используется, add_url_rule()
предлагает некоторые преимущества по сравнению с ним.
Функция-обработчик обязательна должна возвращать строку. Любая попытка вернуть другой тип данных приведет к ошибке 500 Internal Server Error.
Неограниченное количество маршрутов можно добавить к вашему приложению. В следующем примере создаются три различных маршрута:
@app.route('/') def index(): return 'Home Page' @app.route('/career/') def career(): return 'Career Page' @app.route('/feedback/') def feedback(): return 'Feedback Page'
Если маршрут оканчивается на слеш (/), и он пропущен в запросе, Flask автоматически добавит его. Так, запрос /career
будет перенаправлен на /career/
.
Один и тот же URL можно привязывать к множеству функций отображения. Например:
@app.route('/contact/') @app.route('/feedback/') def feedback(): return 'Feedback Page'
Этот пример кода показывает, что запросы на /contact/
и /feedback/
вызовут функцию feedback()
.
Если ввести URL, для которого не назначена функция-обработчик, было бы наподобие того, чтобы обратиться к чему-либо несуществующему: мы получаем ошибку 404 Not Found.
Сущность современного приложения также включает динамичные URL, содержащие изменяемые части, которые влияют на вывод страницы. Например, при проектировании веб-приложения со страницей профиля каждый пользователь имеет уникальный ID. Поэтому профиль пользователя будет доступен по адресу /user/1
, у сущности по адресу /user/2
и т.д. Однако создание маршрутов для каждого пользователя по отдельности крайне неудобно.
Для решения этой проблемы динамические части URL можно обозначать как <variable_name>
. Эти компоненты затем передаются в функцию отображения в виде ключевых слов. Пример кода с динамическим элементом:
@app.route('/user/<id>/') def user_profile(id): return "Profile page of user #{}".format(id)
В этом примере часть <id> будет заменена на часть URI, следующую после /user/
. Если вы зайдете по адресу /user/100/, приложение выдаст следующий ответ:
Profile page of user #100
Динамический элемент URL не ограничен числовыми ID. Он может принимать значения вроде /user/cowboy/
, /user/foobar10/
и даже /user/@@##/
. Исключением являются URI, такие как /user/
и /user/12/post/
. Чтобы ограничить маршрут числовыми ID, можно воспользоваться конвертерами.
Изначально динамические части URL-адреса передаются функции в виде строк, но это можно изменить посредством конвертера, который указывают перед динамическими частями <converter:variable_name>
. Например: /user/<int:id>/
будет корректным для путей типа /user/1/
, /user/200/
и т.д. Однако пути вроде /user/cowboy/
, /user/foobar10/
и /user/@@##/
не подойдут.
Конвертеры, доступные в Flask:
Конвертер | Описание |
---|---|
string | принимает любые строки (значение по умолчанию). |
int | принимает целые числа. |
float | принимает числа с плавающей точкой. |
path | принимает полный путь, включая промежуточные и завершающие слэши. |
uuid | принимает UUID строки. |
Запуск сервера
Чтобы запустить сервер, можете воспользоваться методом run()
экземпляра Flask.
if __name__ == "__main__": app.run()
Строка __name__ == "__main__"
обеспечивает выполнение метода run()
только тогда, когда main.py запускается как исполняемая программа. Так, если импортировать main.py в другом модуле, метод run()
не сработает.
Важно! Разработчики Flask настоятельно предупреждают, что сервер разработки предназначен исключительно для тестирования и обладает ограниченной производительностью.
Сейчас у вас должно сложиться более четкое представление о работе main.py.
Режим отладки (Debug)
Ошибки в процессе программирования неизбежны, и важно уметь находить их и устранять. В Flask присутствует мощный встроенный отладчик, который по умолчанию выключен. Если отладчик не включен, а в коде имеется ошибка, фреймворк предоставляет стандартный ответ 500 Internal Server Error. Например, добавим ошибку в main.py:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): print(i) return 'Hello World' if __name__ == "__main__": app.run()
Теперь программа выводит значение несуществующей переменной i, что приводит к ошибке. При обращении к http://127.0.0.1:5000/ видим сообщение об ошибке 500:
Однако, даже хотя браузер не раскрывает информации о типе ошибки, в консоли можно увидеть более детальное описание:
File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request rv = self.dispatch_request() File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "main.py", line 13, in index print(i) NameError: name 'i' is not defined
Если отладка отключена, сервер придется перезапускать вручную после каждого изменения в коде, чтобы увидеть обновления. В режиме отладки сервер перезапускается автоматически при каждом изменении.
Чтобы включить отладку, укажите debug=True при вызове метода run()
:
if __name__ == "__main__": app.run(debug=True)
Альтернативный способ — задать значение debug как True:
from flask import Flask app = Flask(__name__) app.debug = True
Теперь main.py будет выглядеть следующим образом:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): print(i) return 'Hello World' if __name__ == "__main__": app.run(debug=True) # включение режима отладки
Перезапустив сервер, при ошибке откроется HTML-страница с подробной информацией об ошибке. Внизу страницы будет ясно указано, что существующая ошибка связана с неопределенной переменной i и типа NameError.
Кликнув на строчку кода, вы откроете контекст ошибки и сможете просмотреть соседние строки, что облегчит поиск причин неисправности.
Кликните на строчке кода для доступа к консоли, где можно вводить Python-команды.
Консоль позволит вам просмотреть локальные переменные.
При первом открытии консоли требуется ввести PIN-код.
Этот код служит мерой безопасности для предотвращения несанкционированного доступа. Процесс его получения изображен в первой части вывода сервера.
На завершающем этапе урока создадим еще одно приложение на Flask, задействуя изученные знания.
Таким образом, создайте файл main2.py с таким кодом:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello Flask' @app.route('/user/<int:user_id>/') def user_profile(user_id): return "Profile page of user #{}".format(user_id) @app.route('/books/<genre>/') def books(genre): return "All Books in {} category".format(genre) if __name__ == "__main__": app.run(debug=True)
Запустив файл и перейдя по http://127.0.0.1:5000/, получите приветствие "Hello Flask":
Теперь в приложении есть динамические пути. Например, перейдя на http://127.0.0.1:5000/user/123/, вы увидите:
Изначально интернет-адрес /user/<int:user_id>/ сработает лишь на тот, где user_id числовой.
Проверьте второй динамический маршрут, введя http://127.0.0.1:5000/books/sci-fi/, получите:
Текущие адреса, не имеющие указанных маршрутов, вызовут ошибку 404 Not Found. Это случится, если попытаться перейти на http://127.0.0.1:5000/products.
Как Flask обрабатывает запрос?
Как Flask определяет, какую функцию отображать для запроса от клиента?
Flask сопоставляет URL с указанной функцией в декораторе route или через метод add_url_rule()
. Эти данные хранятся в атрибуте url_map экземпляра Flask.
>>> >>> from main2 import app >>> app.url_map Map([<Rule '/' (OPTIONS, GET, HEAD) -> index>, <Rule '/static/<filename>' (OPTIONS, GET, HEAD) -> static>, <Rule '/books/<genre>' (OPTIONS, GET, HEAD) -> books>, <Rule '/user/<user_id>' (OPTIONS, GET, HEAD) -> user_profile>]) >>>
Видно, что в данном случае заданы четыре правила. Flask присваивает маршрут URL в следующем формате:
url-шаблон, (список методов HTTP, которые обрабатывает маршрут) -> функция отображения
Путь /static/<filename> добавляется Flask автоматически для статических файлов. Эти концепции будут более детально изучены в уроке "Обслуживание статических файлов во Flask".