Есть ли автоинкремент для integer id в SQLAlchemy?
Что проверяют
Знаете ли вы, что автоинкремент в SQLAlchemy включается сам и во что он превращается на конкретной базе. Следом спрашивают, когда у объекта появляется id и как быть с составным ключом.
Как отвечать
Да, и включать его явно обычно не нужно. У Column параметр autoincrement по умолчанию равен "auto": если первичный ключ состоит из одной целочисленной колонки без внешнего ключа и без заданного default, SQLAlchemy считает её автоинкрементной. В стиле 2.0 достаточно id: Mapped[int] = mapped_column(primary_key=True).
Что появится в DDL, зависит от диалекта:
- PostgreSQL:
SERIALдляIntegerиBIGSERIALдляBigInteger. Для стандартной identity-колонки есть конструкцияIdentity(), она даётGENERATED BY DEFAULT AS IDENTITY; - MySQL:
AUTO_INCREMENT; - SQLite:
INTEGER PRIMARY KEYстановится псевдонимомrowidи заполняется автоматически. Ключевое словоAUTOINCREMENT, запрещающее повторное использование номеров, добавляетsqlite_autoincrement=Trueв__table_args__; - Oracle: нужен
Identity()или явныйSequence.
Значение выдаёт база, поэтому до flush() у нового объекта id равен None. После session.flush() или commit() ORM забирает его, на PostgreSQL через RETURNING.
Для составного ключа "auto" ничего не включает: autoincrement=True ставится явно на нужную колонку, и поддерживается это не всеми базами.
Где спотыкаются
Ставят autoincrement=True на колонку вне первичного ключа и ждут счётчик. Параметр действует только на колонки первичного ключа, для остальных нужен Identity() или серверный default.
Пишут declarative_base из sqlalchemy.ext.declarative и session.query. Это устаревший стиль: в 2.0 базовый класс наследуют от DeclarativeBase, а запросы строят через select().
Ждут непрерывную нумерацию. Последовательность не откатывается при ROLLBACK, поэтому дыры в id нормальны, и строить логику на плотности номеров нельзя.