Python Alembic迁移不';无法正确生成UUID

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

事实上确实如此,但我肯定做错了什么

我有一个数据库,我在表上创建了一个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) 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