You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have compare_server_default=True and am running alembic revision --autogenerate. I am changing primary key column from int to uuid and have compare_server_default enabled to help with server_default=func.gen_random_uuid(). Sometimes autogenerate recognizes the existing pk sequences, sometimes it does not, leading to a new migration file that's empty, or sometimes contains a change applying server_default=None. Using postgres 15.x
Expected behavior
I'm still new to postgres/alembic/sqlalchemy, so I don't know what the desired behavior is. However, I would expect a deterministic result.
To Reproduce
When I am running autogenerate this is basically my models.py:
And the database has these defaults for the tables:
Table "public.parent"
Column | Type | Collation | Nullable | Default
---------------------------+--------------------------+-----------+----------+--------------------------------------
pk | integer | | | nextval('parent_pk_seq'::regclass)
id | uuid | | not null | gen_random_uuid()
Table "public.child"
Column | Type | Collation | Nullable | Default
---------------------------+--------------------------+-----------+----------+--------------------------------------
pk | integer | | | nextval('child_pk_seq'::regclass)
id | uuid | | not null | gen_random_uuid()
Error
autogenerate creates a file with upgrade/downgrade function that contain either 0, 1, or 2 alter_columns:
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('parent', 'pk',
existing_type=sa.INTEGER(),
server_default=None,
existing_nullable=True)
op.alter_column('child', 'pk',
existing_type=sa.INTEGER(),
server_default=None,
existing_nullable=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('child', 'pk',
existing_type=sa.INTEGER(),
server_default=sa.text("nextval('child_pk_seq'::regclass)"),
existing_nullable=True)
op.alter_column('parent', 'pk',
existing_type=sa.INTEGER(),
server_default=sa.text("nextval('parent_pk_seq'::regclass)"),
existing_nullable=True)
# ### end Alembic commands ###
For no operations, the log looks like this:
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.ddl.postgresql] Detected sequence named 'parent_pk_seq' as owned by integer column 'parent(pk)', assuming SERIAL and omitting
INFO [alembic.ddl.postgresql] Detected sequence named 'child_pk_seq' as owned by integer column 'child(pk)', assuming SERIAL and omitting
INFO [alembic.ddl.postgresql] Detected sequence named 'association_table_pk_seq' as owned by integer column 'association_table(pk)', assuming SERIAL and omitting
For 1 operation it can look like this:
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.ddl.postgresql] Detected sequence named 'parent_pk_seq' as owned by integer column 'parent(pk)', assuming SERIAL and omitting
INFO [alembic.ddl.postgresql] Detected sequence named 'association_table_pk_seq' as owned by integer column 'association_table(pk)', assuming SERIAL and omitting
INFO [alembic.autogenerate.compare] Detected server default on column 'child.pk'
Versions.
OS: debian
Python: 3.11
Alembic: 1.13.1
SQLAlchemy: 2.0.29
Database: postgresql 15.4
DBAPI: asyncpg 0.29.0
Additional context
The order in which the tables are reflected seems to matter and is random. The alter_column operations are added when association_table is reflected before the other(s). I played around with the resolve_fks: bool = True-argument in the functionreflect_table: with this boolean set to False, the output is consistent no matter the other the tables are reflected in. The log output can end up being:
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.ddl.postgresql] Detected sequence named 'child_pk_seq' as owned by integer column 'child(pk)', assuming SERIAL and omitting
INFO [alembic.ddl.postgresql] Detected sequence named 'association_table_pk_seq' as owned by integer column 'association_table(pk)', assuming SERIAL and omitting
INFO [alembic.ddl.postgresql] Detected sequence named 'parent_pk_seq' as owned by integer column 'parent(pk)', assuming SERIAL and omitting
Although association_table is reflected before parent here, it does not result in an alter_column operation in the migration file.
When I looked at locals() inside autogenerate/compare.py::_compare_server_default, when child and/or parent was reflected thanks to resolve_fks=True, the variable conn_col_default had a value of DefaultClause(<sqlalchemy.sql.elements.TextClause object at 0x..........>, for_update=False) which holds the string nextval('child_pk_seq'::regclass) (or parent_pk_seq of course). When association_table is reflected last, or with resolve_fks=False, the variable conn_col_default is always None.
The text was updated successfully, but these errors were encountered:
Can you also post the previous status of your models before you updated them?
The issue here seems that alembic does some assumptions regarding what's a serial and what is not. That on itself should be fine, but not that the behaviour changes randomly
Describe the bug
I have
compare_server_default=True
and am runningalembic revision --autogenerate
. I am changing primary key column from int to uuid and havecompare_server_default
enabled to help withserver_default=func.gen_random_uuid()
. Sometimes autogenerate recognizes the existing pk sequences, sometimes it does not, leading to a new migration file that's empty, or sometimes contains a change applyingserver_default=None
. Using postgres 15.xExpected behavior
I'm still new to postgres/alembic/sqlalchemy, so I don't know what the desired behavior is. However, I would expect a deterministic result.
To Reproduce
When I am running autogenerate this is basically my models.py:
And the database has these defaults for the tables:
Error
autogenerate creates a file with upgrade/downgrade function that contain either 0, 1, or 2 alter_columns:
For no operations, the log looks like this:
For 1 operation it can look like this:
Versions.
Additional context
The order in which the tables are reflected seems to matter and is random. The
alter_column
operations are added whenassociation_table
is reflected before the other(s). I played around with theresolve_fks: bool = True
-argument in the functionreflect_table
: with this boolean set to False, the output is consistent no matter the other the tables are reflected in. The log output can end up being:Although
association_table
is reflected beforeparent
here, it does not result in analter_column
operation in the migration file.When I looked at locals() inside
autogenerate/compare.py::_compare_server_default
, whenchild
and/orparent
was reflected thanks toresolve_fks=True
, the variableconn_col_default
had a value ofDefaultClause(<sqlalchemy.sql.elements.TextClause object at 0x..........>, for_update=False)
which holds the stringnextval('child_pk_seq'::regclass)
(or parent_pk_seq of course). When association_table is reflected last, or withresolve_fks=False
, the variableconn_col_default
is alwaysNone
.The text was updated successfully, but these errors were encountered: