1

Problem

I'm using Alembic autogenerate to migrate some model changes. I run alembic revision/upgrade once and it properly creates my table and adds an alembic_version table to my database. When I go to run the revision/upgrade command again, it tries to recreate the table despite no changes being made to the model

alembic.command.revision(cfg, autogenerate=True)
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'alias.alias'

As you can see here it's attempting to add the table alias.alias even though it already exists in my database and was created by Alembic in the first revision/upgrade command.

Database after first revision

Predictably, when I attempt to run the second upgrade I get the error

psycopg2.errors.DuplicateTable: relation "alias" already exists

Current setup

env.py

import sys
import os
sys.path.insert(0, '/tmp/')

from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from models.Base import Base
from models import Alias

config = context.config

fileConfig(config.config_file_name)

target_metadata = Base.metadata

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,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )

    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.

    """
    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
        )

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


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

Alias.py

from sqlalchemy import Column, Integer, String
from models.Base import Base


class Alias(Base):
    __tablename__ = 'alias'
    __table_args__ = {'schema': 'alias'}

    id = Column(Integer, primary_key=True)
    chart_config = Column(String)
    name = Column(String, nullable=False, unique=True)
    display_name = Column(String)
    datasets = Column(String)

Base.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

Expected outcome

How do I get alembic to detect that the alias.alias table already exists? It should autogenerate an empty revision. The model Alias.py is completely static during my 2 runs of revision/upgrade

Spothedog1
  • 349
  • 2
  • 3
  • 10

1 Answers1

-1

Solved by editing alembic's env.py to include schemas

    with connectable.connect() as connection:
    context.configure(
        connection=connection, target_metadata=target_metadata,
        include_schemas = True # Include this
    )

    with context.begin_transaction():
        context.run_migrations()
Spothedog1
  • 349
  • 2
  • 3
  • 10