自动生成迁移时如何使 alembic 或 flask 迁移名称外键?
How to make alembic or flask migrate name foreign keys when autogenerating migrations?
我断断续续地为这个问题苦苦挣扎了很长一段时间,奇怪的是在 SO 上找不到直接的 question/answer 组合。相关问题here and here。我终于找到了解决方案,所以我会提出并回答我自己的问题。
在 Flask SQLAlchemy(和常规 SQLAlchemy)中,您可以拥有这样的列:
class Character(db.model):
background_id = db.Column(db.Integer, db.ForeignKey('backgrounds.id'))
当您 运行 flask db migrate
或 alembic revision --autogenerate
时,这将导致如下所示的操作:
def upgrade():
op.create_foreign_key(None, 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(None, 'characters', type_='foreignkey')
这里的None
不好。事实上,如果你稍后尝试降级,这总是会失败,因为 drop_constraint
需要约束的名称。
您可以在每次生成迁移时更改它,如下所示:
def upgrade():
op.create_foreign_key('fk_characters_backgrounds', 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint('fk_characters_backgrounds', 'characters', type_='foreignkey')
哪个有效!
但是,如果您像我一样,不想每次使用外键自动生成修订版时都必须记住执行此操作。
所以问题是,我们怎样才能让它自动进行?
在“命名约定的重要性”部分末尾建议的最佳实践 here 中找到了这个问题的答案。解决方案是将 naming_convention
添加到 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)
更具体地说,使用 Flask-SQLAlchemy
,在初始化数据库时执行此操作:
from sqlalchemy import MetaData
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"
}
db = SQLAlchemy(metadata=MetaData(naming_convention=convention))
瞧!如果你 运行 autogenerate
,你会得到这个:
def upgrade():
op.create_foreign_key(op.f('fk_characters_background_id_backgrounds'), 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(op.f('fk_characters_background_id_backgrounds'), 'characters', type_='foreignkey')
感谢(意料之中的)Flask Migrate 的创建者 Miguel Grinberg,感谢他链接到 Alembic 文档中的正确页面,最终让我解决了这个问题! Someone had asked about this in an issue on Flask Migrate GitHub,他正确地指出这是一个 Alembic 问题,而不是 Flask Migrate 问题。
我断断续续地为这个问题苦苦挣扎了很长一段时间,奇怪的是在 SO 上找不到直接的 question/answer 组合。相关问题here and here。我终于找到了解决方案,所以我会提出并回答我自己的问题。
在 Flask SQLAlchemy(和常规 SQLAlchemy)中,您可以拥有这样的列:
class Character(db.model):
background_id = db.Column(db.Integer, db.ForeignKey('backgrounds.id'))
当您 运行 flask db migrate
或 alembic revision --autogenerate
时,这将导致如下所示的操作:
def upgrade():
op.create_foreign_key(None, 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(None, 'characters', type_='foreignkey')
这里的None
不好。事实上,如果你稍后尝试降级,这总是会失败,因为 drop_constraint
需要约束的名称。
您可以在每次生成迁移时更改它,如下所示:
def upgrade():
op.create_foreign_key('fk_characters_backgrounds', 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint('fk_characters_backgrounds', 'characters', type_='foreignkey')
哪个有效!
但是,如果您像我一样,不想每次使用外键自动生成修订版时都必须记住执行此操作。
所以问题是,我们怎样才能让它自动进行?
在“命名约定的重要性”部分末尾建议的最佳实践 here 中找到了这个问题的答案。解决方案是将 naming_convention
添加到 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)
更具体地说,使用 Flask-SQLAlchemy
,在初始化数据库时执行此操作:
from sqlalchemy import MetaData
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"
}
db = SQLAlchemy(metadata=MetaData(naming_convention=convention))
瞧!如果你 运行 autogenerate
,你会得到这个:
def upgrade():
op.create_foreign_key(op.f('fk_characters_background_id_backgrounds'), 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(op.f('fk_characters_background_id_backgrounds'), 'characters', type_='foreignkey')
感谢(意料之中的)Flask Migrate 的创建者 Miguel Grinberg,感谢他链接到 Alembic 文档中的正确页面,最终让我解决了这个问题! Someone had asked about this in an issue on Flask Migrate GitHub,他正确地指出这是一个 Alembic 问题,而不是 Flask Migrate 问题。