Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Define ignored tables in alembic.ini

Add this in your ini file:

[alembic:exclude]
tables = spatial_ref_sys

In env.py:

def exclude_tables_from_config(config_):
    tables_ = config_.get("tables", None)
    if tables_ is not None:
        tables = tables_.split(",")
    return tables

exclude_tables = exclude_tables_from_config(config.get_section('alembic:exclude'))


def include_object(object, name, type_, reflected, compare_to):    
    if type_ == "table" and name in exclude_tables:
        return False
    else:
        return True

def run_migrations_offline():
    """Run migrations in 'offline' mode.

    This configures the context with just a URL
    and not an Engine, though an Engine is acceptable
    here as well.  By skipping the Engine creation
    we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the
    script output.

    """
    # url = config.get_main_option("sqlalchemy.url")
    context.configure(url=engine.url, include_object=include_object)

    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    if isinstance(engine, Engine):
        connection = engine.connect()
    else:
        raise Exception('Expected engine instance got %s instead' % type(engine))

    context.configure(
        connection=connection,
        target_metadata=target_metadata,
        include_object=include_object
    )

    try:
        with context.begin_transaction():
            context.run_migrations()
    finally:
        connection.close()
@wandonye

This comment has been minimized.

Copy link

@wandonye wandonye commented Dec 18, 2014

Looks like this is the solution I was looking for. But I got this error: NameError: global name 'engine' is not defined.

@wandonye

This comment has been minimized.

Copy link

@wandonye wandonye commented Dec 18, 2014

Probably some version discrepancy. This one works for me:
def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well.  By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url, include_object = include_object)

with context.begin_transaction():
    context.run_migrations()

def run_migrations_online():
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""
engine = engine_from_config(
            config.get_section(config.config_ini_section),
            prefix='sqlalchemy.',
            poolclass=pool.NullPool)

connection = engine.connect()
context.configure(
            connection=connection,
            target_metadata=target_metadata,
            include_object = include_object
            )

try:
    with context.begin_transaction():
        context.run_migrations()
finally:
    connection.close()
@getadeo

This comment has been minimized.

Copy link

@getadeo getadeo commented Mar 9, 2016

Hi,

Thanks for this. Big help.

@petrus-jvrensburg

This comment has been minimized.

Copy link

@petrus-jvrensburg petrus-jvrensburg commented Mar 15, 2016

Thanks tor this 👍

@peterlada

This comment has been minimized.

Copy link

@peterlada peterlada commented May 31, 2016

👍

@kopf

This comment has been minimized.

Copy link

@kopf kopf commented Jan 3, 2017

You can get rid of the first function altogether by just doing

exclude_tables = config.get_section('alembic:exclude').get('tables', '').split(',')

@qholnessMD

This comment has been minimized.

Copy link

@qholnessMD qholnessMD commented Jan 25, 2018

This is great!
Thank you.

@jdheywood

This comment has been minimized.

Copy link

@jdheywood jdheywood commented Nov 14, 2019

Awesome 💯 thanks

@vincent-prz

This comment has been minimized.

Copy link

@vincent-prz vincent-prz commented Apr 14, 2020

Super useful, thanks!

@JWDobken

This comment has been minimized.

Copy link

@JWDobken JWDobken commented Apr 25, 2020

Very helpful!

@javiergarciad

This comment has been minimized.

Copy link

@javiergarciad javiergarciad commented Jun 2, 2020

Very Helpful Kudos !! 👍 👍

@utek

This comment has been minimized.

Copy link
Owner Author

@utek utek commented Jun 2, 2020

After 6 years this gist is still being used :) Thank you :)

@juanuys

This comment has been minimized.

Copy link

@juanuys juanuys commented Nov 12, 2020

If you want to use it in the main config section, and want to support YAML lists:

[alembic]
exclude_tables =
    quux
    eggs, foo,
    ham, bar
    baz
def get_list_from_config(config, key):
    arr = config.get_main_option(key, [])
    if arr:
        # split on newlines and commas, then trim (I mean strip)
        arr = [token for a in arr.split('\n') for b in a.split(',') if (token := b.strip())]
    return arr


exclude_tables = get_list_from_config(config, "exclude_tables")

To get

['quux', 'eggs', 'foo', 'ham', 'bar', 'baz']

@CircleOnCircles

This comment has been minimized.

Copy link

@CircleOnCircles CircleOnCircles commented Nov 21, 2020

If you want to use it in the main config section, and want to support YAML lists:

[alembic]
exclude_tables =
    quux
    eggs, foo,
    ham, bar
    baz
def get_list_from_config(config, key):
    arr = config.get_main_option(key, None)
    if arr is not None:
        # split on newlines and commas, then trim (I mean strip)
        arr = [token for a in arr.split('\n') for b in a.split(',') if (token := b.strip())]
    return arr


exclude_tables = get_list_from_config(config, "exclude_tables")

To get

['quux', 'eggs', 'foo', 'ham', 'bar', 'baz']

+1

@Fingel

This comment has been minimized.

Copy link

@Fingel Fingel commented Dec 2, 2020

I've found that both alembic.ini and the first few functions and calls in the gist can be greatly simplified:

In alembic ini simply add a value in the main config section (by sqlalchemy.url, for example):

# Exclude the following tables from being detected for migrations
exclude = spatial_ref_sys

And in env.py all you need is:

exclude_tables = config.get_main_option('exclude', '').split(',')


def include_object(object, name, type_, *args, **kwargs):
    if type_ == 'table' and name in exclude_tables:
        return False
    else:
        return True

Then just edit run_migrations_offline and run_migrations_online to use the newly defined include_object function just like the original gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment