Search
Write a publication
Pull to refresh

Comments 6

Также алхимию можно применять в любой проекте, в то время как ORM от Django недоступен в отрыве от основного фреймворка.

Это не правда https://github.com/dancaron/Django-ORM

Не говоря уже о том, что Django это делает гораздо элегантнее и с встроенной поддержкой миграций.

Спасибо за наводку. Я натыкался на сторонние библиотеки, но использовать их в prod-е я бы не стал. Жду поддержки отдельно ORM именно от Django-проекта.

Ну это не совсем библиотека, это просто шаблон "как подключить Django и убрать ненужное". Прям отдельно ORM сами Django вряд ли будут делать т.к. в этом нет никакого интереса для них. А для использования в проектах можно и руками это сделать.

Видимо, придётся написать статью-ответ. Но то, что называется в данной статье "оптимизацией" таковой не является. По крайней мере, не всегда. А для конкретных листингов оптимизацией было бы что-то вроде (что-то вокруг #sa.9.1, #sa.9.2):

query = sa\
  .select(Topic.id.label('id'), sa.func.array_agg(User.name).label('users'))\
  .where(sa.and_(
    Topic.id == TopicUser.topic_id,
    TopicUser.user_id == User.id
  ))\
  .group_by(sa.literal_column('1'))

with session as s:
  for row in s.execute(query):
    print(f'Topic {row.id}, Users: {", ".join(row.users)}')

Не надо запрашивать то, что не требуется. Если требуется получить только определенные колонки, не надо просить ORM вытащить модель целиком. Гонять новый запрос на каждую строчку связанной модели - моветон. Если средства СУБД позволяют объединить (или схлопнуть несколько строк в одну без потери данных - позвольте это сделать СУБД. Она, во-первых, скорее всего, сделает это эффективнее, во-вторых, будет меньше накладных расходов на запрос и передачу result tuples.

Более того, мой запрос прочитает, скорее всего, даже далёкий от Python DBA. А запрос с мутаторами для relationship mapping - не всякий, там уже надо ковырять детали и тонкости конкретного движка (в данном случае - SA).

query = sa\
  .select(Topic.id.label('id'), sa.func.array_agg(User.name).label('users'))\
  .where(sa.and_(
    Topic.id == TopicUser.topic_id,
    TopicUser.user_id == User.id
  ))\
  .group_by(sa.literal_column('1'))

with session as s:
  for row in s.execute(query):
    print(f'Topic {row.id}, Users: {", ".join(row.users)}')

А как, простите, дебажить такие запросы? А когда у тебя SELECT более чем на 10 таблиц?

ORM не подходит для крупных проектов и больших команд. С этим сложнее работать.

А как все другие запросы дебажить предполагается?

SELECT
  topics.id             AS id,
  array_agg(users.name) AS users
FROM
  topics,
  topics_users,
  users
WHERE
  topics.id = topics_users.topic_id
  AND
  topics_users.user_id = users.id
GROUP BY 1

Вот же этот запрос. Он в SQLAlchemy выглядит один-в-один, как в SQL (в отличие от другой популярной но, на мой взгляд, кривущей реализации ORM в Python).

Как его дебажить?

Более того, в моём случае запрос сначала пишется в DataGrip (sql server client console), отлаживается, смотрится план выполнения, затем переносится в SQLAlchemy. Тривиальные запросы, конечно, можно и без отладки в консоли написать.

Sign up to leave a comment.