12

I am having a problem creating an initial migration which would automatically have tables that I've defined in my models.py by using shared Base (declarative_base).

When I enter a command:

alembic revision --autogenerate

alembic creates an empty file.

What's wrong in my configs or my approach?

project.base.py:

from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()

env.py:

import sys
import os

sys.path.append(os.path.abspath(os.getcwd()))
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig

from project.base import Base
target_metadata = Base.metadata
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
    )

    # target_metadata.reflect(engine, only=[
    #     "django_migrations",
    #     "auth_group_permissions",
    #     "django_session",
    #     "auth_user_user_permissions",
    #     "auth_user_groups",
    #     "django_admin_log",
    #     "auth_permission",
    #     "auth_user",
    #     "sysdiagrams",
    #     "django_content_type",
    #     "auth_group",
    #     "sysdiagrams",
    # ])

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


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

Sample model:

# -*- coding: utf-8 -*-

from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey, SmallInteger
from sqlalchemy.orm import relationship, backref
from project.base import Base


__schema__ = "Users"


class User(Base):
    __tablename__ = "User"
    __table_args__ = {'schema': __schema__}

    USER_CUSTOMER = 0
    USER_EMPLOYEE = 5
    USER_ADMIN = 10

    USER_TYPES = (
        (USER_CUSTOMER, u'Klient'),
        (USER_EMPLOYEE, u'Obsługa sklepu'),
        (USER_ADMIN, u'Administrator')
    )

    id = Column(Integer, primary_key=True)
    name = Column(String(255))
    email = Column(String(255))
    password = Column(String)
    date_created = Column(DateTime)
    date_updated = Column(DateTime)
    user_type = Column(SmallInteger)

    is_active = Column(Boolean)

    def __repr__(self):
        return u"<User: ({} {})>".format(self.id, self.name)

    def is_management(self):
        return self.user_type in [self.USER_EMPLOYEE, self.USER_ADMIN]

    def is_admin(self):
        return self.user_type == self.USER_ADMIN

Edit:

I've discovered that Base.metadata.sorted_tables is empty.

taras
  • 6,566
  • 10
  • 39
  • 50
Efrin
  • 2,323
  • 3
  • 25
  • 45

1 Answers1

21

In addition to importing your declarative Base class, you also need to import all of your models as well. Something like import project.models or whatever module(s) you have to include so that all your model classes are imported. Otherwise, your Base.metadata doesn't get populated with your model definitions since env.py never includes them.

dgilland
  • 2,758
  • 1
  • 23
  • 17
  • 2
    If you're like me, and already had the table defined, make sure to rename the existing tables e.g. with the `_old` suffix, perform your alembic generate, delete the extra drop statements in the auto-gen script (it will find your renamed tables and generate drop/create statements), and finally rename the tables back. There should probably be an `--init` option you can pass to auto-generate so that its not this roundabout... – smaudet Oct 10 '19 at 10:18