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".
Hello World во фреймворке Flask

Остановить сервер можно сочетанием клавиш 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:
ошибка 500 Internal Sever Error

Однако, даже хотя браузер не раскрывает информации о типе ошибки, в консоли можно увидеть более детальное описание:

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-команды.

консоль, где можно ввести любой код Python

Консоль позволит вам просмотреть локальные переменные.

локальные переменные

При первом открытии консоли требуется ввести PIN-код.

Если консоль открывается первый раз, то нужно ввести PIN-код

Этот код служит мерой безопасности для предотвращения несанкционированного доступа. Процесс его получения изображен в первой части вывода сервера.

#3 Основы Flask Посмотреть код можно в консоли при запуске сервера

На завершающем этапе урока создадим еще одно приложение на 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":

Hello Flask

Теперь в приложении есть динамические пути. Например, перейдя на http://127.0.0.1:5000/user/123/, вы увидите:

http://127.0.0.1:5000/user/123/

Изначально интернет-адрес /user/<int:user_id>/ сработает лишь на тот, где user_id числовой.

Проверьте второй динамический маршрут, введя http://127.0.0.1:5000/books/sci-fi/, получите:

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".

Вопросы для самопроверки:

  1. Какая команда используется для запуска Flask-приложения в виртуальном окружении Python?
  2. Что такое WSGI, и как оно связано с Flask-приложением?
  3. Как включить режим отладки в Flask-приложении?
  4. Что произойдет, если ввести URL, для которого не назначена функция-обработчик в Flask?
  5. Какие данные отображаются в консоли при ошибке выполнения кода Flask-приложения в выключенном режиме отладки?