alembic autogenerates 创建空迁移但生成 table

alembic autogenerates creates empty migration but generates table

我按照 Alembic 的 documentation 来自动生成迁移。我的项目结构如下所示:

alembic/
  versions/
  env.py
  README
  script.py.mako
data/
  __init__.py
  db.py
  models.py
alembic.ini
app.db

我完全按照文档对 env.py 进行了更改:

from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context
from data.models import Base

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = Base.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


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

这是我的 __init__.py:

import os

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from .models import Base

basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
db_url = os.environ.get('DATABASE_URL') or \
         'sqlite:///' + os.path.join(basedir, 'app.db')
engine = create_engine(db_url, echo=False)
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)

我在 models.py 中创建了一个用户 class,如下所示:

from sqlalchemy import Column, Sequence, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()    

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    first_name = Column(String, nullable=False)
    last_name = Column(String, nullable=False)

    def __repr__(self):
        return "<%s('%s', '%s')>" \
               % (self.__class__.__qualname__, self.first_name,
                  self.last_name)

之后,我 运行 迁移方式:

alembic revision --autogenerate -m "Added user table"

但是,我在迁移文件中得到了空的 upgrade() 和 downgrade():

"""Added user table

Revision ID: 279933caec54
Revises: 
Create Date: 2021-05-12 16:21:05.772568

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '279933caec54'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ### 

但是当我查看数据库时,那里创建了用户table(我自己没有这样做)。它怎么发生的? alembic 如何创建空迁移但生成 table?

我在这个中找到了答案。不过,这个问题中描述的问题与我的不同(在这种情况下,alembic 没有创建一个空的迁移文件)。这就是为什么我在这里问这个问题(可能被视为重复)。

因此,按照答案的建议,我在 __init__.py 中评论了 Base.metadata.create_all(engine)。正是这行代码创建了用户 table(如果它不存在)。因此,当 alembic 检查我的数据库时,table 已经存在。由于没有发现差异,upgrade() 和 downgrade() 为空。