Книга: FastAPI: веб-разработка на Python
Назад: Глава 6. Зависимости
Дальше: Часть III. Создание веб-сайта

Глава 7. Сравнение фреймворков

Вам не нужен каркас. Вам нужна картина, а не ее рама.

Клаус Кински, актер

Обзор

Для разработчиков, ранее использовавших Flask, Django или другие популярные веб-фреймворки Python, эта глава указывает на их сходство с FastAPI и отличия от него. Здесь не рассматриваются все утомительные подробности, потому что иначе клей для переплета не удержит эту книгу целой. Сравнения, приведенные здесь, могут быть полезны, если вы думаете о переносе приложения с одного из этих фреймворков на FastAPI или просто любопытствуете.

Одна из первых вещей, которую вы можете узнать о новом веб-фреймворке, — это как начать работу, и путь сверху вниз — это определение маршрутов (связки между URL-адресами и HTTP-методами и функциями). В следующем разделе мы сравним, как выполнить эту задачу с помощью FastAPI и Flask, поскольку они более похожи друг на друга, чем Django, и, скорее всего, будут рассматриваться вместе для похожих приложений.

Flask

Разработчики 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

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

В настоящее время три основных веб-фреймворка на 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 позволяет ему во многих случаях работать быстрее своих конкурентов. Далее: давайте уже создадим сайт.


Цитата отражает некую игру слов, поскольку в английском языке слово frame­­work означает каркас, а не только привычный разработчикам фреймворк. — Примеч. пер.

Назад: Глава 6. Зависимости
Дальше: Часть III. Создание веб-сайта