Вам не нужен каркас. Вам нужна картина, а не ее рама.
Клаус Кински, актер
Для разработчиков, ранее использовавших Flask, Django или другие популярные веб-фреймворки Python, эта глава указывает на их сходство с FastAPI и отличия от него. Здесь не рассматриваются все утомительные подробности, потому что иначе клей для переплета не удержит эту книгу целой. Сравнения, приведенные здесь, могут быть полезны, если вы думаете о переносе приложения с одного из этих фреймворков на FastAPI или просто любопытствуете.
Одна из первых вещей, которую вы можете узнать о новом веб-фреймворке, — это как начать работу, и путь сверху вниз — это определение маршрутов (связки между URL-адресами и HTTP-методами и функциями). В следующем разделе мы сравним, как выполнить эту задачу с помощью FastAPI и Flask, поскольку они более похожи друг на друга, чем Django, и, скорее всего, будут рассматриваться вместе для похожих приложений.
Разработчики Flask (https://flask.palletsprojects.com) называют его микрофреймворком. Он предоставляет базовые возможности, а вы загружаете сторонние пакеты, чтобы дополнить их по мере необходимости. Он меньше, чем Django, и в начале работы его можно быстрее освоить.
Flask относится к типу синхронных и создан на базе стандарта WSGI, а не ASGI. Новый проект под названием quart (https://quart.palletsprojects.com) воспроизводит Flask и добавляет в него поддержку стандарта ASGI.
Начнем с самого начала, показав, как Flask и FastAPI определяют веб-маршрутизацию.
На верхнем уровне Flask и FastAPI используют декоратор, чтобы связать маршрут с конечной веб-точкой. В примере 7.1 продублируем пример 3.11, в котором человек получает приветствие из URL-пути.
Пример 7.1. Путь FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/hi/{who}")
def greet(who: str):
return f"Hello? {who}?"
По умолчанию FastAPI преобразует строку f"Hello? {who}?" в формат JSON и возвращает ее веб-клиенту.
В примере 7.2 показано, как это сделает Flask.
Пример 7.2. Путь Flask
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/hi/<who>", methods=["GET"])
def greet(who: str):
return jsonify(f"Hello? {who}?")
Обратите внимание на то, что слово who в декораторе теперь заключено в угловые скобки (< и >). Во Flask метод должен быть включен в качестве аргумента, если только по умолчанию не используется GET. Следовательно, выражение methods= ["GET"] можно было бы и опустить, но ясность никогда не помешает.
Flask 2.0 поддерживает декораторы в стиле FastAPI, такие как @app.get, вместо app.route.
Функция jsonify() из Flask преобразует аргумент в строку формата JSON и возвращает ее вместе с заголовком HTTP-ответа, указывающим на то, что это формат JSON. Если вы возвращаете данные типа dict (а не другие типы данных), последние версии Flask автоматически конвертируют его в JSON и возвращают. Вызов функции jsonify() явно работает для всех типов данных, включая dict.
В примере 7.3 повторим пример 3.15, где who передается в качестве параметра запроса (после символа ? в URL-адресе).
Пример 7.3. Параметр запроса FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/hi")
def greet(who):
return f"Hello? {who}?"
Эквивалент Flask показан в примере 7.4.
Пример 7.4. Параметр запроса Flask
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/hi", methods=["GET"])
def greet():
who: str = request.args.get("who")
return jsonify(f"Hello? {who}?")
Во Flask нам нужно получить значения запроса из объекта request. В данном случае аргумент args относится к типу dict и содержит параметры запроса.
В примере 7.5 скопируем старый пример 3.21.
Пример 7.5. Тело запроса FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/hi")
def greet(who):
return f"Hello? {who}?"
Версия Flask выглядит как в примере 7.6.
Пример 7.6. Тело запроса Flask
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/hi", methods=["GET"])
def greet():
who: str = request.json["who"]
return jsonify(f"Hello? {who}?")
Flask хранит входные данные в формате JSON в файле request.json.
Наконец, повторим пример 3.24 в примере 7.7.
Пример 7.7. Заголовок FastAPI
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/hi")
def greet(who:str = Header()):
return f"Hello? {who}?"
Версия Flask показана в примере 7.8.
Пример 7.8. Заголовок Flask
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/hi", methods=["GET"])
def greet():
who: str = request.headers.get("who")
return jsonify(f"Hello? {who}?")
Как и в случае с параметрами запроса, Flask хранит данные запроса в объекте request. В данном случае это будет атрибут headers типа dict. Ключи заголовков должны быть нечувствительны к регистру.
Django (https://www.djangoproject.com) — это более крупный и сложный проект, чем Flask или FastAPI, ориентированный на «перфекционистов со сроками», как утверждается на его сайте. Встроенное объектно-реляционное связывание (Object-Relational Mapper, ORM) полезно для сайтов с основными бэкендами баз данных. Это скорее монолит, чем набор инструментов. Оправданны ли трудности обучения и освоение дополнительных сложностей, зависит от ваших задач.
Хотя Django был традиционным WSGI-приложением, в версии 3.0 была добавлена поддержка стандарта ASGI.
В отличие от Flask и FastAPI, Django предпочитает определять маршруты (связывая URL с веб-функциями, которые он называет функциями представления) в одной таблице URLConf, а не с помощью декораторов. Это облегчает просмотр всех маршрутов в одном месте, но затрудняет понимание того, какой URL связан с функцией, когда вы смотрите только на саму функцию.
В предыдущих разделах, посвященных сравнению трех фреймворков, я в основном сравнивал способы определения маршрутов. От веб-фреймворка можно ожидать помощи и в других областях.
• Формы — все три пакета поддерживают стандартные HTML-формы.
• Файлы — все эти пакеты работают с выгрузкой и скачиванием файлов, включая многокомпонентные HTTP-запросы и ответы.
• Шаблоны — язык шаблонов позволяет смешивать текст и код и полезен для контент-ориентированного сайта (HTML-текст с динамически вставляемыми данными), а не для сайта с API. Наиболее известным пакетом шаблонов Python является Jinja (https://jinja.palletspro jects.com), и он поддерживается Flask, Django и FastAPI. У Django есть и собственный язык шаблонов (https://oreil.ly/OIbVJ).
Если вы хотите использовать сетевые методы, выходящие за рамки базового HTTP, попробуйте следующие варианты.
• Server-sent events (SSE) — передает данные клиенту по мере необходимости. Поддерживается FastAPI (sse-starlette, https://oreil.ly/Hv-QP), Flask (Flask-SSE, https://oreil.ly/oz518) и Django (Django EventStream, https://oreil.ly/NlBE5).
• Очереди — очереди заданий, публикация-подписка и другие сетевые шаблоны поддерживаются такими внешними пакетами, как ZeroMQ, Celery, Redis и RabbitMQ.
• WebSockets — поддерживаются FastAPI (непосредственно), Django (Django Channels, https://channels.read thedocs.io) и Flask (сторонние пакеты).
В базовые пакеты Flask и FastAPI не включена работа с базами данных, но она является ключевой особенностью Django.
Уровень данных вашего сайта может обращаться к базе данных на разных уровнях:
• непосредственно SQL (PostgreSQL, SQLite);
• непосредственно NoSQL (Redis, MongoDB, Elasticsearch);
• ORM, генерирующее SQL;
• объектное связывание документов (Object Document Mapping, ODM), генерирующее NoSQL.
Для реляционных баз данных SQLAlchemy (https://www.sqlalchemy.org) — отличный пакет, включающий в себя несколько уровней доступа, от прямого SQL до ORM. Это обычный выбор для разработчиков Flask и FastAPI. Автор FastAPI использовал как SQLAlchemy, так и Pydantic для пакета SQLModel (https://sqlmodel.tiangolo.com) — о нем мы подробнее поговорим в главе 14.
Django часто выбирают в качестве фреймворка для сайтов с большими потребностями в базах данных. У него есть свои ORM (https://oreil.ly/eFzZn) и автоматизированная страница администрирования баз данных (https://oreil.ly/_al42). Хотя некоторые источники рекомендуют разрешить нетехническому персоналу использовать страницу администратора для рутинного управления данными, будьте осторожны. Однажды я видел, как неспециалист неправильно понял предупреждающее сообщение на странице администратора, в результате чего базу данных пришлось восстанавливать вручную из резервной копии.
В главе 14 более подробно рассматриваются FastAPI и базы данных.
Для сервисов на базе API лучшим выбором кажется FastAPI. Flask и FastAPI примерно равны в плане скорости запуска сервиса. Чтобы разобраться в Django, потребуется больше времени, но он предоставляет множество возможностей, полезных для больших сайтов, особенно сильно зависящих от баз данных.
В настоящее время три основных веб-фреймворка на Python — это Flask, Django и FastAPI. Введите в Google запрос python web frameworks, и вы получите множество предложений, которые я не буду здесь приводить. Среди тех, которые, возможно, не выделяются в этих списках, но интересны по тем или иным причинам, можно назвать следующие:
• Bottle (https://bottlepy.org/docs/dev) — минимальный (один файл Python) пакет, хорошо подходящий для того, чтобы быстро доказать концепцию;
• Litestar (https://litestar.dev) — похож на FastAPI — основан на ASGI/Starlette и Pydantic, но представляет иной взгляд на поставленную задачу;
• AIOHTTP (https://docs.aiohttp.org) — клиент и сервер ASGI с полезным демонстрационным кодом;
• Socketify.py (https://docs.socketify.dev) — новый участник, потенциально очень высокопроизводительный.
Flask и Django — самые популярные веб-фреймворки на Python, хотя популярность FastAPI растет быстрее. Все три они справляются с основными задачами веб-сервера, но скорость их освоения разная. У FastAPI, похоже, более чистый синтаксис для задания маршрутов, а поддержка ASGI позволяет ему во многих случаях работать быстрее своих конкурентов. Далее: давайте уже создадим сайт.
Цитата отражает некую игру слов, поскольку в английском языке слово framework означает каркас, а не только привычный разработчикам фреймворк. — Примеч. пер.