Pull to refresh

Comments 24

Я указал этот момент в разделе «Сравнение с остальными ОРМ».
Сейчас в документации описано что это beta версия. Нужно какое то время подождать исправления всех проблем, на данный момент использовать эту версию с привязкой к asyncio рискованно
1.4 уже довольно давно зарелизилась, а я использовал -dev версию в проде ещё до её выхода.

У peewee асинхронная версия это отдельный проект, который отставал на несколько версий от синхронной версии(возможно, это уже не так).

В django есть костыли в виде sync_to_async/async_to_sync.

А вот tortoise мне понравился больше всего, сейчас для каких-то небольших проектов, типа ботов на aiogram, я беру именно её.
спасибо за подробный ответ!
В планах — попробовать асинхронную алхимию на одном из новых некритичных сервисов, и если она себя хорошо покажет — можно тиражировать этот опыт.
Но я думаю что ORM не подойдёт для сложных нагруженных сервисов, т к для разработчика не всегда понятна как она построит тот или иной запрос и не «положит ли бд» в каких то граничных случаях. Запросы без ORM гораздо проще прогнозировать и проверять через explain
Если знать как орм работает, то всё понятно. Кроме того, в django, например достаточно написать str(queryset) чтобы увидеть sql-запрос, есть ключил --print-sql в shell_plus который будет сразу печатать все sql запросы, которые выполняются. Есть debug_toolbar и silk которые покажут все sql запросы на странице и время их выполнение. Есть метод queryset.explain() docs.djangoproject.com/en/3.2/topics/db/optimization

В алхимии есть аналогичные средства, их даже больше т.к. она более навороченная и с её помощью можно выразить вообще любые запросы.

Но главное — это то, что запросы можно конструировать динамически, из кусочков. Например, добавлять условия в зависимости от параметров запроса. На «голом» sql это будет кошмар. Есть конструкторы запросов, но почему бы не использовать сразу orm. Потому что помимо этого орм обеспечивает средства для автоматических миграций и т.п. При наличие декларативных моделей можно автоматически создавать сериализаторы github.com/pawnhearts/aiorf/blob/master/aiorf/saschema.py и т.п.

А свою объектку менее рискованно?

Данная обёртка и полноценная ORM — разные вещи
В данном случае используется 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

Спасибо! происследую реализацию
Мы во многих проектах используем Gino, вполне себе удобная и адекватная библиотека, не вижу смысла придумывать свои велосипеды, только вот:
Работать с этой библиотекой можно без знаний об SQLAlchemy.

это не совсем так — gino это по сути надстройка над SQLAlchemy Сore, поэтому если умеешь писать запросы на алхимии, то в gino по сути все тоже самое, особых проблем с переходом не будет.
Идея была такая — можно не учить SQLAlchemy Сore, достаточно документации самой Gino
Добрый день!
Когда добавите producer на статью «11 друзей Sanic’а – собираем асинхронное веб-приложение на Python»
Добрый день!
А что подразумевается под producer? Отправка сообщений в очередь(consumer/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')

данный кусочек на отдельную статью не тянет, может мимоходом упомяну в какой нибудь будущей публикации

Sign up to leave a comment.