当前位置: 首页 > 知识库问答 >
问题:

'alembic修订版--autogen'产生冗余外键迁移

岳劲
2023-03-14

软件版本:alembic 1.0.5、SQLAlchemy 1.2.14、MySQL 5.7、Python 3.6.7

我试图使用alembic来保持MySQL数据库模式和Python ORM表示的一致性。

我看到的问题是,迁移总是有多余的外键删除和创建命令。autogenerate似乎认为有些东西是不同的,但实际上它们是相同的。

在重复调用命令时:

alembic revision --autogenerate 
alembic upgrade head

...将生成相同的拖放和创建命令。

stdout的日志显示如下内容(例如):

INFO  [alembic.autogenerate.compare] Detected removed foreign key (t1_id)(id) on table table_two
INFO  [alembic.autogenerate.compare] Detected added foreign key (t1_id)(id) on table test_fktdb.table_two

迁移脚本包括:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('fk_table1', 'table_two', type_='foreignkey')
    op.create_foreign_key('fk_table1', 'table_two', 'table_one', ['t1_id'], ['id'], source_schema='test_fktdb', referent_schema='test_fktdb')
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint('fk_table1', 'table_two', schema='test_fktdb', type_='foreignkey')
    op.create_foreign_key('fk_table1', 'table_two', 'table_one', ['t1_id'], ['id'])
    # ### end Alembic commands ###

这个问题是可以复制的,我举了一个简单的例子(tar.gz)https://github.com/sqlalchemy/alembic/files/2625781/FK_test.tar.gz).示例中的ORM类似于:

[...import and bobs...]

class TableOne(Base):
    """Class representing a table with an id."""
    __tablename__ = "table_one"

    id = Column(UNSIGNED_INTEGER, nullable=False, autoincrement=True, primary_key=True)

    __table_args__ = (
        dict(mysql_engine='InnoDB'),
    )


class TableTwo(Base):
    """A table representing records with a foreign key link to table one."""
    __tablename__ = "table_two"

    id = Column(UNSIGNED_INTEGER, nullable=False, autoincrement=True, primary_key=True)
    t1_id = Column(UNSIGNED_INTEGER, nullable=False)

    __table_args__ = (
        ForeignKeyConstraint(["t1_id"], ["test_fktdb.table_one.id"], name="fk_table1"),
        dict(mysql_engine='InnoDB'),
    )

有什么方法可以使数据库中的FK与ORM中的FK相同?例如,通过env.py应用一些配置?

我环顾了一下这个问题,在alembic GitHub中发现了一些旧问题(请参见[1]、[2]、[3])。有解决方案的问题似乎涉及postgres数据库和公共模式。我不确定这是否适用于本例,因为我使用的是MySQL;公共postgres模式的相关文档如下:https://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#remote-模式表内省和postgresql搜索路径

我现在在alembic GitHub回购协议中添加了我自己的问题:https://github.com/sqlalchemy/alembic/issues/519

alembic问题跟踪器中的封闭问题,表现出类似的症状,但其解决方案不适用(据我所知):

[1] https://github.com/sqlalchemy/alembic/issues/444

[2]https://github.com/sqlalchemy/alembic/issues/398

[3] https://github.com/sqlalchemy/alembic/issues/293

共有1个答案

法子昂
2023-03-14

所以,虽然这个问题很古老,给了我风滚草徽章,但我认为回答它并关闭它会很好。我在GitHub上从包维护人员Mike Bayer那里得到了一个很好的答案:

好吧,事情是这样的。您正在连接数据库URL中的“test_fktdb”作为默认模式。这意味着,alembic将在该模式中查找您的表,当它找到外键时,它将看到该FK中的“schema_name”字段为空,因为这是默认模式。所以它与元数据中的内容不匹配。此外,您没有向环境中添加“include_schemas=True”,因此当您的ORM模型中包含“schema='test_fktdb'”时,您肯定不会得到合理的结果。

你可以进入两个普遍的世界来解决这个问题。

>

  • 简单一点。完全从表/元数据/外键中删除“schema”。然后,在test_fktdb中,所有内容都作为默认值工作,并且所有内容都匹配。

    很难。你需要连接到URL上的另一个数据库,然后在你的环境中设置include_schemas=True,你可能还需要一个合理的include_object()方案,这样它就不会读取所有其他数据库,设置version_table_schema='test_fktdb',然后也可以:

    env.py:
    
    SCHEMA_NAME = "NOT_test_fktdb"
    
        def include_object(object, name, type_, reflected, compare_to):
            if (type_ == "table"):
                return object.schema == "test_fktdb"
    
            else:
                return True
    
        with connectable.connect() as connection:
            context.configure(
                connection=connection,
                target_metadata=target_metadata,
                compare_type=True,
                compare_server_default=True,
                include_schemas=True,
                version_table_schema="test_schema",
                include_object=include_object
            )
    
           # ...
    

    “模式”逻辑必然严重依赖于“默认”模式是一个空白字符串的概念,因此,当你混淆了默认模式也存在时,它会混淆事情。

    GitHub上还有更多内容https://github.com/sqlalchemy/alembic/issues/519.

    我发现这个简单的选择奏效了,我做了以下改变:

    # instead of [...]:
    # declarative_base(metadata=sqlalchemy.MetaData(schema=test_fktdb.SCHEMA_NAME))
    Base = sqlalchemy.ext.declarative.declarative_base()
    
    # instead of [...]:
    # ForeignKeyConstraint(["t1_id"], ["test_fktdb.table_one.id"], name="fk_table1"),
    ForeignKeyConstraint(["t1_id"], ["table_one.id"], name="fk_table1"),
    

  •  类似资料:
    • 我试图理解维基百科上规范的DFS伪代码(http://en.wikipedia.org/wiki/Depth-first_search)--特别是使用堆栈的非递归实现。 在BFS中,您在将节点推送到队列之前检查它是否已经被探索过,这保证了不会有节点被多次推送到队列上。但是在DFS中,只有当您将节点从堆栈中弹出时,才会检查它是否已经被探索。这似乎是故意的,正如维基百科页面所说:“[DFS]推迟检查是

    • 问题内容: 我正在使用Alembic处理Flask的迁移。理论上,应该基于数据库中的更改自动生成迁移。但是,Alembic仅使用上述命令即可生成空白迁移。 有一个与此问题非常相似的问题,即问题是没有导入正确的模型。但是,我已经从我的Flask应用程序导入了模型,如下所示: 以及中导入的数据库元数据env.py(“ start”是我的Flask应用程序主文件的名称): 运行,alembic revi

    • 我有一个项目,我在模型中使用SQLAlchemy,并尝试集成Alembic进行迁移。当我更改模型时,一切都按预期进行,Alembic看到模型已经更改- 但是当我没有改变模型中的任何东西并且我使用相同的命令时: 修订版给我“空”修订版文件,如下所示: 这个文件的目的是什么?当alembic revision--autogenerate看不到任何更改时,我可以阻止创建这个“空文件”吗?要比较使用Dja

    • 我使用的是Eclipselink2.3.2提供的JPA2.0。 在这种情况下,可以通过在这两个表之间使用联接来更好地处理它,而不是使用子查询,但编写这样的子查询而不在其中使用冗余联接是可能的,因为这是一个相当基本的事情。 编辑1: 我看不出这个例外背后有什么理由。 编辑3: 在最新版本中的相同条件查询--在例外情况下失败的查询--在Hibernate(4.2.7 final)提供的JPA上没有任何

    • 我正在尝试用React-Native构建我的第一个应用程序。 我正在遵循这两个教程: https://facebook.github.io/react-native/docs/gett-started.html#content https://facebook.github.io/react-native/docs/android-setup.html 我尝试安装Android build too

    • Git 允许你通过几种方法来指明特定的或者一定范围内的提交。 了解它们并不是必需的,但是了解一下总没坏处。 单个修订版本 你可以通过 Git 给出的 SHA-1 值来获取一次提交,不过还有很多更人性化的方式来做同样的事情。 本节将会介绍获取单个提交的多种方法。 简短的 SHA-1 Git 十分智能,你只需要提供 SHA-1 的前几个字符就可以获得对应的那次提交,当然你提供的 SHA-1 字符数量不