【问题标题】:Alembic recreates foreign keys every time I migrate causing duplicate foreign keys on my tables每次我迁移时,Alembic 都会重新创建外键,导致表上出现重复的外键
【发布时间】:2020-03-29 14:35:57
【问题描述】:

我有一个烧瓶应用程序,使用 sql-alchemy 和烧瓶迁移来处理数据库更改。每次我运行烧瓶迁移为 Alembic 创建脚本以更新数据库时,该脚本都包含用于创建已存在于我的数据库中的外键的命令。

我的models.py中的表定义是

class Airline(db.Model):

    __tablename__ = 'Airlines'
    AirlineID =         db.Column(db.Integer,       primary_key=True)
    AirlineShortCode =  db.Column(db.String(3),     index=True, unique=True, nullable=False)
    FullName =          db.Column(db.String(256),   unique=False, nullable=True)
    ShortName =         db.Column(db.String(64),    unique=False, nullable=True)

class CabinClass(db.Model):

    __tablename__ = 'CabinClasses'
    CabinClassID =         db.Column(db.Integer,     primary_key=True)
    AirlineShortCode =     db.Column(db.ForeignKey("Airlines.AirlineShortCode"), nullable=True)
    CabinClassShortCode =  db.Column(db.String(32),  unique=False, nullable=False)
    CabinClassName =       db.Column(db.String(64),  unique=False, nullable=True)

迁移数据库更新脚本中为创建外键而生成的行是

    op.create_foreign_key(None, 'CabinClasses', 'Airlines', ['AirlineShortCode'], ['AirlineShortCode'])

我每次创建迁移脚本时都会生成这一行,导致 CabinClasses 表中有多个外键条目:

我看到创建的每个外键的名称都不同,并且数据库迁移脚本中的create_foreign_key 命令将名称声明为None。如果您使用自动命名方案,我相信这是正确的,我相信这是默认情况下发生的情况

对于使用自动命名方案的设置,如所述 在配置约束命名约定,这里的名称可以是无, 因为事件侦听器会将名称应用于约束对象 当它与表关联时

https://alembic.sqlalchemy.org/en/latest/naming.html

谁能确定每次我更新数据库时都会创建这些外键的原因?

【问题讨论】:

    标签: python sqlalchemy flask-sqlalchemy alembic flask-migrate


    【解决方案1】:

    您获得的约束名称看起来像是来自您的数据库,而不是 SQLAlchemy。您需要将所有类型约束的约束命名模板添加到 SQLAlchemy 元数据中,然后我认为您将获得一致的名称。在 Flask-SQLAlchemy documentation 中查看如何执行此操作。为了您的方便,我从以下文档中复制了代码示例:

    from sqlalchemy import MetaData
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    convention = {
        "ix": 'ix_%(column_0_label)s',
        "uq": "uq_%(table_name)s_%(column_0_name)s",
        "ck": "ck_%(table_name)s_%(constraint_name)s",
        "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
        "pk": "pk_%(table_name)s"
    }
    
    metadata = MetaData(naming_convention=convention)
    db = SQLAlchemy(app, metadata=metadata)
    

    【讨论】:

    • 谢谢@miguel,我实现了这个并运行了一个db migrate(我正在使用你的flask-migrate(它很棒))。这创建了一个 Alembic 迁移文件,其中 create_foreign_key 语句填充了新的命名约定。 op.create_foreign_key(op.f('fk_CabinClasses_AirlineShortCode_Airlines'), 'CabinClasses', 'Airlines', ['AirlineShortCode'], ['AirlineShortCode']) 我进行了升级并添加了外键,但是,当运行进一步的 db 迁移时,它创建了与上次完全相同的 create_foreign_key 行,使用新的命名约定。
    猜你喜欢
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2014-04-03
    • 2019-04-30
    • 2023-01-04
    • 2013-04-01
    相关资源
    最近更新 更多