I'm using alembic to manage database migrations as per user defined sqlalchemy models. My challenge is that I'd like for alembic to ignore any creation, deletion, or changes to a specific set of tables.
Note: My Q is similar to this question Ignoring a model when using alembic autogenerate but is different in that I want to control alembic from outside the model definition.
Here's a sample table I want to ignore:
from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base(metadata=MetaData())
class Ignore1(Base):
"""
Signed in to the account...
"""
__tablename__ = 'ignore_1'
__table_args__ = {
'info':{'skip_autogenerate':True}
}
id = Column(Integer, primary_key=True)
foo = Column(String(20), nullable=True)
Example code (which does not solve my issue):
In alembic/env.py
# Ideally this is stored in my actual database, but for now, let's assume we have a list...
IGNORE_TABLES = ['ignore_1', 'ignore_2']
def include_object(object, name, type_, reflected, compare_to):
"""
Should you include this table or not?
"""
if type_ == 'table' and (name in IGNORE_TABLES or object.info.get("skip_autogenerate", False)):
return False
elif type_ == "column" and object.info.get("skip_autogenerate", False):
return False
return True
# Then add to config
context.configure(
...
include_object=include_object,
...
)
Alembic can view the status of the database and compare against the table metadata in the application, generating the “obvious” migrations based on a comparison. This is achieved using the --autogenerate option to the alembic revision command, which places so-called candidate migrations into our new migrations file.
Alembic generates a table in the project table space called alembic_version that keeps track of the unique ID of the last version file applied to the schema. During an update, Alembic uses this stored version ID to determine what if any follow on version files to process.
Alembic provides for the creation, management, and invocation of change management scripts for a relational database, using SQLAlchemy as the underlying engine. This tutorial will provide a full introduction to the theory and usage of this tool.
I found a solution to my problem!
My error was in the instantiation of my context
object in env.py
def run_migrations_offline():
...
context.configure(
url=url,
target_metadata=target_metadata,
include_object=include_object,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
I wasn't applying this change to context for online migrations:
def run_migrations_online():
...
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
# THE FOLLOWING LINE WAS MISSING FROM MY ORIGINAL CODE
include_object=include_object, # <----------------------- THIS!
)
...
Hopefully anyone else encountering this issue and experiencing similar turmoil can read through my question & following solution and recognize that despair is but a small dumb tweak from salvation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With