Pull to refresh

Comments 12

Хорошая статья, полезно будет для новичков

Но ведь алхимия 1.4 уже асинхронная, даже core. Нужна ли всё ещё дополнительная обёртка в виде Gino?

Добрый день!

Да, действительно SQLAlchemy, начиная с 1.4 уже имеет встроенную поддержку asyncio, что позволяет не использовать Gino в большинстве asyncio-проектов. При этом в статье мы рассказываем про Gino по двум причинам:

1) Gino не только обеспечивает асинхронность для SQLAlchemy - он также  добавляет различные фичи, поэтому он не станет "мертвым грузом" в проекте. Вот, например, что пишут сами разработчики Gino по поводу добавления поддержки asyncio в SQLAlchemy и как они планируют развивать Gino дальше: https://python-gino.org/docs/en/1.0/how-to/faq.html#sqlalchemy-1-4-supports-asyncio-what-will-gino-be

2) Большинство проектов нашей компании используют Gino, так как стартовали до выхода SQLAlchemy 1.4. Эту статью мы даем студентам наших курсов - потенциальным будущим стажерам -  в качестве доп. материала и поэтому нам хотелось бы, чтобы они учились тому, что используем мы.

Спасибо за вопрос, добавлю в статью упоминание о SQLAlchemy 1.4 для полной картины

Спасибо за туториал. Очень увлекательно для новичка. Есть пара советов для тех, кто будет с нуля повторять по шагам:
1. SQLAlchemy по умолчанию встанет версией, несовместимой с Gino - надо переставить, какую pip подскажет. Иначе генератор миграций не будет работать
2. В тексте пропущен момент, что надо еще реализовать функции upgrade() и downgrade(). Реализации не сложные, найти можно в репозитории с исходниками

Спасибо большое за замечания!

В ближайшем времени добавлю их в статью.

Начал добавлять к статье Ваши замечания и понял, что они не совсем актуальны:
1. SQLAlchemy по материалам статьи не устанавливается явно - она устанавливается, как зависимость Gino, что гарантирует, что версия SQLAlchemy будет совместима с версией Gino.
2. Действительно функции upgrade() и downgrade() можно написать самостоятельно, но по материалам статьи они автогенерируются связкой SQLAlchemy + Alembic (см. 7 — Генерируем миграцию)

В любом случае постараюсь побольше акцентировать внимание на этих вещах. Еще раз спасибо!

Спасибо за отклик. Я все же на своем буду настаивать
1. В вашем requirements.txt alembic указан выше Gino, поэтому вероятнее всего сначала будет удовлетворена зависимость alembic. Если посмотреть выхлоп pipdeptree:

SQLAlchemy==1.3.24
  - alembic==1.5.2 [requires: SQLAlchemy>=1.3.0]
  - gino==1.0.1 [requires: SQLAlchemy>=1.2.16,<1.4]

видно, что встанет версия >=1.3.0 и скорее всего самая последняя стабильная

2. Я не про то, что их самостоятельно писать надо. Они генерируются, но пустые, т.е. в теле функции только pass. Может я что-то делаю не так?

Чтобы это заработало нужно импортировать модель Message, в migrations/env.py

Добрый день!

1. Вы правы, порядок модулей в requirements.txt неверен, поправил.


2. Здесь мной также допущена ошибка, миграции действительно не автогенерировались в таком окружении. Дело в том, что Alembic видит только те модели, которые были импортированы в момент генерации миграций. Соответственно в коде статьи модель Message не была импортирована и Alembic ее не видел. Скорее всего импорт был, но так как явно его ничего не использовало, то он был убран при оптимизации. Чтобы таких ситуации больше не возникало и миграции могли быть автоматически сгенерированы, я добавил в функцию run_migrations_online в файл migrations/env.py импорт и инстанцирование PostgresAccessor, который в свою очередь импортирует все нужные модели. Теперь модели будут в памяти при генерации миграций и импорт будет использован явно.

Большое спасибо Вам, что заметили ошибки и настояли на своем мнении!

def setup_routes(application):
    from app.forum.routes import setup_routes as setup_forum_routes
async def _on_connect(self, application: web.Application):
    from app.store.database.models import db

вы действительно учите новичков вот таким подходам?

Добрый день!

Если Ваше замечание касается локальных импортов, то Вы правы - здесь они излишни. Видимо они были добавлены в первую итерацию написания кода для этой статьи и в свое время "развязывали" циклические импорты. В текущей версии кода они не нужны, поправил это, спасибо за замечание.

Для новичков можно сказать, что использования локальных импортов необходимо в двух случаях:
1. При кольцевых импортах. То есть когда разные модули вашего приложения импортят друг друга по кругу.
2. Для повышения скорости первоначального запуска вашего приложения. "Ленивые" импорты позволяют не загружать при запуске все модули, а подгружать их по мере необходимости.

Критической ошибки в локальных импортах нет - код в большинстве случаев будет исполняться как и задумано. Хочу заметить три нюанса из моей практики, связанных с локальными импортами:
1. В одном файле два объекта могут импортировать один и тот же модуль локально - соответственно он будет импортирован два раза локально, вместо одного глобального, что повлияет на производительность.
2. Сколько раз будет исполнен код с импортом - столько раз модуль будет импортирован. Это может повлиять на производительность. В статье функции с локальными импортами исполняются один раз, поэтому разницы между глобальным и локальным импортом немного.
3. Импорт наверху файла улучшает читаемость кода - при взгляде на файл, сразу видно что он использует и с чем он связан.

Sign up to leave a comment.