Python Alembic迁移不';无法正确生成UUID
事实上确实如此,但我肯定做错了什么 我有一个数据库,我在表上创建了一个FK,在未来的迁移中,它被删除了 因此,表的create语句是:Python Alembic迁移不';无法正确生成UUID,python,sqlalchemy,migration,uuid,alembic,Python,Sqlalchemy,Migration,Uuid,Alembic,事实上确实如此,但我肯定做错了什么 我有一个数据库,我在表上创建了一个FK,在未来的迁移中,它被删除了 因此,表的create语句是: CREATE TABLE this_table ( pk INTEGER NOT NULL, some_other_table_pk INTEGER, CONSTRAINT "fk_436d3a57-0ae2-5668-937d-8cbc82d15172" FOREIGN KEY(some_other_table_pk
CREATE TABLE this_table (
pk INTEGER NOT NULL,
some_other_table_pk INTEGER,
CONSTRAINT "fk_436d3a57-0ae2-5668-937d-8cbc82d15172" FOREIGN KEY(some_other_table_pk) REFERENCES some_other_table (pk)
然后我删除约束,alembic自动生成以下批处理操作:
def upgrade():
with op.batch_alter_table('this_table', schema=None) as batch_op:
# how does it know here which fk to drop? there are more than one???
batch_op.drop_constraint(None, type_='foreignkey')
batch_op.drop_column('some_other_table_pk')
def downgrade():
with op.batch_alter_table('this_table', schema=None) as batch_op:
batch_op.add_column(sa.Column('some_other_table_pk', sa.INTEGER(), nullable=True))
batch_op.create_foreign_key(None, 'some_other_table_pk', ['some_other_table'], ['pk'])
这导致升级头上出现错误:
KeyError: 'fk_ad156c6d-7a24-5d8e-868e-2fb00c2cb1c9'
很明显,它没有重新生成相同的密钥?!?
密钥与此表上的任何fk都不匹配。。。
但它如何知道生成哪个密钥呢?drop_约束未获取有关要删除哪个fk的任何信息
我的元数据约定:
def fk_guid(constraint, table):
str_tokens = [
table.name,
] + [
element.parent.name for element in constraint.elements
] + [
element.target_fullname for element in constraint.elements
]
guid = uuid.uuid5(uuid.NAMESPACE_OID, "_".join(str_tokens))
return str(guid)
convention = {
"fk_guid": fk_guid,
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(column_0_name)s",
"fk": "fk_%(fk_guid)s",
"pk": "pk_%(table_name)s",
}
metadata = MetaData(naming_convention=convention)
Base = declarative_base(metadata=metadata)
在env.py中:
# ...
target_metadata = models.Base.metadata
# ...
def run_migrations_offline():
url = getUrl()
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
render_as_batch=True,
dialect_opts={"paramstyle": "named"},
compare_type=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
alembic_config = config.get_section(config.config_ini_section)
connectable = create_engine(getUrl())
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
render_as_batch=True,
dialect_opts={"paramstyle": "named"},
compare_type=True
)
with context.begin_transaction():
context.run_migrations()
数据库是一个sqlite3文件
开始编辑
因此,我尝试手动传入要删除的约束的名称:
def upgrade():
with op.batch_alter_table('this_table', schema=None) as batch_op:
batch_op.drop_constraint('fk_436d3a57-0ae2-5668-937d-8cbc82d15172', type_='foreignkey')
batch_op.drop_column('some_other_table_pk')
现在它导致了一个密钥错误,但是密钥应该存在于数据库中
KeyError: 'fk_436d3a57-0ae2-5668-937d-8cbc82d15172'
编辑结束
开始编辑2
好的,我在沙盒中玩了一点,如果是drop_约束,似乎是用户定义的令牌密钥不适用于升级:
仅当创建约束时,才会调用以下情况下的fk_guid
convention = {
"fk_guid": some_function,
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(column_0_name)s",
"fk": "fk_%(fk_guid)s",
# "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
并提供以下用于创建和删除的迁移代码:
sa.ForeignKeyConstraint(['table_b'], ['table_b.id'], name=op.f('fk_9d68bd30-b17a-565a-aee7-7bd21e90672e')),
# But for dropping, it's not generated:
batch_op.drop_constraint(None, type_='foreignkey')
但奇怪的是,在alembic upgrade head
上调用了一些函数
,但与创建调用的约束条件不同:
def fk_guid(constraint, table):
str_tokens = [
table.name,
] + [
element.parent.name for element in constraint.elements
] + [
element.target_fullname for element in constraint.elements
]
print(f'string_tokens: {str_tokens}')
guid = uuid.uuid5(uuid.NAMESPACE_OID, "_".join(str_tokens))
return str(guid)
def some_function(*params):
print(f'params: {params}')
return fk_guid(*params)
输出:
string_tokens: ['table_a']
将外键的命名约定更改为标准
convention = {
"fk_guid": some_function,
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(column_0_name)s",
# "fk": "fk_%(fk_guid)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
根据需要进行创建和删除:
# creation:
sa.ForeignKeyConstraint(['table_b'], ['table_b.id'], name=op.f('fk_table_a_table_b_table_b')),
# dropping:
batch_op.drop_constraint('fk_table_a_table_b_table_b', type_='foreignkey')
编辑结束2
开始编辑3
github上有一个线程:
编辑3的结尾我还没有找到这个问题的答案。。。有人吗?我建议你命名你的约束以便调试这个。你所拥有的似乎是自动生成的,从这里很难理解`约束名称是使用UUID自动生成的,还是我误解了一些基本的东西?即使我告诉alembic去掉约束的确切名称,它似乎也找不到它。太好了,你解决了它!,你为什么不把这个问题和答案分开,这样任何人都可以从你的发现中受益。@cheche,我不会说解决方案,这是一个解决方案,它仍然不能与SQLITE3一起工作。我还没有找到这个问题的答案。。。有人吗?我建议你命名你的约束以便调试这个。你所拥有的似乎是自动生成的,从这里很难理解`约束名称是使用UUID自动生成的,还是我误解了一些基本的东西?即使我告诉alembic去掉约束的确切名称,它似乎也找不到它。太好了,你解决了它!,你为什么不把这个问题和答案分开,这样任何人都可以从你的发现中受益。@cheche,我不会说解决方案,这是一个解决方案,但它仍然不适用于sqlite3