Комментарии 24
Сейчас в документации описано что это beta версия. Нужно какое то время подождать исправления всех проблем, на данный момент использовать эту версию с привязкой к asyncio рискованно
У peewee асинхронная версия это отдельный проект, который отставал на несколько версий от синхронной версии(возможно, это уже не так).
В django есть костыли в виде sync_to_async/async_to_sync.
А вот tortoise мне понравился больше всего, сейчас для каких-то небольших проектов, типа ботов на aiogram, я беру именно её.
В планах — попробовать асинхронную алхимию на одном из новых некритичных сервисов, и если она себя хорошо покажет — можно тиражировать этот опыт.
Но я думаю что ORM не подойдёт для сложных нагруженных сервисов, т к для разработчика не всегда понятна как она построит тот или иной запрос и не «положит ли бд» в каких то граничных случаях. Запросы без ORM гораздо проще прогнозировать и проверять через explain
В алхимии есть аналогичные средства, их даже больше т.к. она более навороченная и с её помощью можно выразить вообще любые запросы.
Но главное — это то, что запросы можно конструировать динамически, из кусочков. Например, добавлять условия в зависимости от параметров запроса. На «голом» sql это будет кошмар. Есть конструкторы запросов, но почему бы не использовать сразу orm. Потому что помимо этого орм обеспечивает средства для автоматических миграций и т.п. При наличие декларативных моделей можно автоматически создавать сериализаторы github.com/pawnhearts/aiorf/blob/master/aiorf/saschema.py и т.п.
А свою объектку менее рискованно?
В данном случае используется SQLAlchemy Core, он хорошо оттестирован, и обёртка нужна для уменьшения кол-ва кода и большей читаемости запросов
Я не имею ничего против статьи. Как образовательный материал — это очень хорошо. Но тянуть такое в прод я бы не стал. Возможно дело в моём травматическом опыте выпиливания "обертки" на алхимией.
В данном случае совершенно непонятно чем User.select()
лучше чем select(User)
. Первое — ваше изобретение, второе — стандартный синтаксис. Очевидно, что новые члены команды будут порываться использовать второе. Я понимаю, что многие вещи вы реализовали, но в алхимии очень много полезных возможностей и в конце концов вам придется реализовать их все. Например, я не вижу having, не уверен насколько оно корректно работает с hybrid_property
, alias
или внешними ключами, ссылающимися на ту же таблицу (возможно проблемы нету, я не проводил эксперименты).
Так же не понятно, зачем ограничиваться core, когда вы и так используете declarative_base
. Если речь идет о сокращении кода — как вы будете решать проблему N+1? Алхимия представляет механизм опций для загрузки relstionship
. Это намного удобнее, чем руками писать джойны и подзапросы.
Есть подозрение, что материал немного устарел, сейчас в sqlalchemy идет работа по снижению отличий crore и orm. В частности рекомендую к ознакомлению Migrating to SQLAlchemy 2.0. В новом синтаксисе вы сначала подготавливаете запросы а потом выполняете их в сессии. При чем async и sync версия отличается только этапом выполнения запроса (фактически await словом в одном вызове). В связи с этим мне кажется, изобретение своего конструктора запросов поверх стандартного не актуальным.
Собственно что в бете? Работа самого async session. Конструкторы запросов и прочие механики работают в синхронной версии точно так же.
Неоднократно вижу, что люди пытаюсь в алхимии в модели запихнуть логику работы с соединением. Это нет очень хорошая идея. Все таки у нас не active record.
С точки зрения разделения зон ответственности, модель должна отвечать только за свои данные: данные экземпляра и как эти данные хранятся в бд. Например, сюда хорошо ложатся гибридные свойства и relationship. Если у вас регулярно фигурируют сложные выборки или агрегации, их можно оформить как отдельные модели (алхимия позволяет указать не имя таблицы, а запрос). За счёт этого мы в дальнейшем можем переиспользовать логику моделей в совершенно разных выборках или даже без непосредственно запросов БД.
Сама же отправка запросов в алхимии реализуется в session. Фактически этот объект представляет собой универсальный репозиторий доступа к хранилищу, который работает с моделями и построенными на основе них запросами.
Как я понимаю, для вас кажется муторным конструировать по месту запросы в том виде как это предлагает алихмия. В этом случае имеет смысл выделить их в отдельные функции или даже классы, но запихивать их в виде статикметодов достаточно странно, так как потом эти статики становятся доступны всем слоям приложения которые получают экземпляр модели, а это выглядит как протекание абстракций. В идеале конечно можно было бы воспользоваться "классическими мапперами", когда в качестве моделей выступают обычные датаклассы, но и грамотное использование моделей может быть быть неотличимо от них
Были идеи по удалению коннекта из функций модели. Но на aiopg это не очень удобно реализовывать. В новых проектах попробую реализовать эту логику через библиотеку databases.
Возможно у Вас есть примеры кода, в котором описанная выше логика реализована?
Удаление коннекта из модели — не более чем стиль, это не влияет на логику. Вам нужна механика превращения запроса в понятный коннектору — он у вас есть. И, вам нужен движок, который это умеет вызывать. Если подумать, получается, что я описываю async session алхимии: await session.execute(query)
. В этом случае вы можете разделить логику подготовки запросов и их выполнения. Или подготовить запрос один раз и переиспользовлать в разных местах.
Что касается databases — я не очень тесно с ним работал. Кажется, там были непонятки с жизненным циклом соединений. Плюс я категорически против подхода "автокоммит": найти потерянный коммит намного проще чем потерянную транзакцию. В этом плане мне нравится подход алхимии. Плюс databases раньше не умели relationship (не знаю, как сейчас).
В целом я бы посоветовал не пытаться сократить простые и очевидные места, которые при этом и так не слишком длинные.
Гляньте ormar, молодая и амбициозная асинхронная django-like орм. Как то случайно наткнулся на неё.
Есть асинхронная ормка ORMAR, тоже написанная на core alchemy
Работать с этой библиотекой можно без знаний об SQLAlchemy.
это не совсем так — gino это по сути надстройка над SQLAlchemy Сore, поэтому если умеешь писать запросы на алхимии, то в gino по сути все тоже самое, особых проблем с переходом не будет.
Когда добавите producer на статью «11 друзей Sanic’а – собираем асинхронное веб-приложение на Python»
А что подразумевается под producer? Отправка сообщений в очередь(consumer/producer)? Или вопрос про продолжение?
с помощью библиотеки aioamqp: https://aioamqp.readthedocs.io/en/latest/api.html?highlight=publish#publishing-messages
в рамках проекта с boilerplate используется в функции consume_handler, когда нужно перекинуть сообщение с ошибкой в очередь с авторазбором
пример кода(канал уже поднят):
await channel.publish(payload=body, exchange_name='exchange', routing_key='routing_key')
данный кусочек на отдельную статью не тянет, может мимоходом упомяну в какой нибудь будущей публикации
Пишем обёртку над SQLAlchemy Сore