python - 即使没有任何更改,Alembic 也会继续创建空的迁移文件

标签 python postgresql sqlalchemy alembic

我正在使用 sqlalchemy、postgres 和 alembic 开发一个应用程序。
项目结构如下:

.
├── alembic.ini
├── main.py
├── migrations
│   ├── env.py
│   ├── README
│   ├── script.py.mako
│   └── versions
├── models
│   ├── base.py
│   ├── datamodel1.py
│   ├── datamodel2.py
│   └── __init__.py
└── requirements.txt

3 directories, 10 files

地点:
models/base.py 的内容是:

from sqlalchemy.ext.declarative.api import declarative_base, DeclarativeMeta

Base: DeclarativeMeta = declarative_base()

models/datamodel1.py 的内容是:

from models.base import Base
from sqlalchemy.sql.schema import Column
from sqlalchemy.sql.sqltypes import String, Date, Float


class Model1(Base):
    __tablename__ = 'model1_table'

    model1_id = Column(String, primary_key=True)
    col1 = Column(String)
    col2 = Column(String)

models/datamodel2.py 的内容是:

from models.base import Base
from sqlalchemy.orm import relationship
from sqlalchemy.sql.sqltypes import String, Integer, Date
from sqlalchemy.sql.schema import Column, ForeignKey


# The many to may relationship table
class Model1Model2(Base):
    __tablename__ = 'model1_model2_table'

    id = Column(Integer, primary_key=True)
    model_1_id = Column(String, ForeignKey('model1.model1_id'))
    model_2_id = Column(Integer, ForeignKey('model2.model2_id'))


class Model2(Base):
    __tablename__ = 'model2_table'

    model2_id = Column(Integer, primary_key=True)
    model2_col1 = Column(String)
    model2_col2 = Column(Date)
    # Many to many relationship
    model1_model2 = relationship('Model1', secondary='model1_model2_table', backref='model1_table')

migrations/env.py 的内容是:

from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context
import sys
sys.path.append('./')



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

config = context.config

# I added the following 2 lines to replace the sqlalchemy.url in alembic.ini file.  
db_string = f'postgresql+psycopg2://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}'
config.set_main_option('sqlalchemy.url', db_string)

# 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
from models.datamodel1 import Model1
from models.datamodel2 import Model2, Model1Model2
from models.base import Base
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"},
        include_schemas=True,
    )

    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,
            include_schemas=True
        )

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


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

至于alembic.ini 文件我没有做任何改动,我只是注释了这行:

sqlalchemy.url = driver://user:pass@localhost/dbname

因为我在 migrations/env.py 中分配了它

当我进行更改并运行 alembic revision --autogenerate -m 'Add new updates' 时,迁移文件会正确生成并且一切都按预期工作。
但是,当我运行 alembic revision --autogenerate -m 'Add new updates' 时没有任何更改,它会在终端中显示:

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.ddl.postgresql] Detected sequence named 'model2_table_model2_id_seq' as owned by integer column 'model2_table(model2_id)', assuming SERIAL and omitting
INFO  [alembic.ddl.postgresql] Detected sequence named 'model1_model2_table_id_seq' as owned by integer column 'model1_model2_table(id)', assuming SERIAL and omitting
  Generating /home/user/projects/dev/project/migrations/versions/45c6fbdbd23c_add_new_updates.py ...  done

它会生成包含以下内容的空迁移文件:

"""Add new updates

Revision ID: 45c6fbdbd23c
Revises: 5c17014a7c18
Create Date: 2021-12-27 17:11:13.964287

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '45c6fbdbd23c'
down_revision = '5c17014a7c18'
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 ###

这是预期的行为还是与我的架构有关?

如何防止 Alembic 在没有更改时生成那些空的迁移文件?

最佳答案

Is this the expected behavior or it has something to do with my architecture?

这是预期的行为。命令 alembic revision --autogenerate 总是创建一个新的迁移文件。如果不存在任何更改,那么它会创建一个空的。

您可以使用 alembic-autogen-check检查您的迁移是否与模型同步。

~ $ alembic-autogen-check
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO: Migrations in sync.

How to prevent Alembic from generating those empty migration files when there are no changes?

此外,alembic-autogen-check 仅在迁移与模型同步时返回零代码。因此,您可以将其用作一个命令

alembic-autogen-check || alembic revision --autogenerate -m 'Add new updates'

不过单独使用好像不太方便

关于python - 即使没有任何更改,Alembic 也会继续创建空的迁移文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70497932/

相关文章:

java - 如何将IntelliJ IDEA 2017.1.2连接到Postgresql

python - 有没有办法将 sqlalchemy 查询中的数据附加到 for 循环内的 pandas 数据框中?

python - 来自请求用户的 django 用户组

python - 切片上限不在列表中的列表的最快方法

python - 我应该如何在 Python 应用程序中存储 API key ?

python - 搜索用户输入

ruby-on-rails - 从数组中提取单个案例

postgresql - Spring JPA Hibernate 在 postgres 中更新时间戳 wo 时区时出错

python - 带边界的 SQLAlchemy 求和函数

python - Gearman + SQLAlchemy - 不断丢失 MySQL 线程