Flask-migrate/alembic - 如何跳过特定的 sqlalchemy 绑定
有什么方法可以使用烧瓶DB迁移 / Alembic跳过绑定?
我有两个使用sqlalchemy_binds的存储库,这些存储库使用了通用数据库,但是数据库是不同的。在我的情况下,成员repo repo使用db 成员
,sqlalchemy_binds = {'uders':userddb_uri}
and Contracts repo repo使用db 合同
,sqlalchemy_bindss sqlalchemy_bindss = {'用户':userdb_uri}
。
我希望成员存储库处理用户
db的迁移,并合同回购以忽略数据库迁移。
我正在尝试使用烧瓶移民来进行初始迁移,以添加用户绑定到合同存储库,这需要对合同
db进行一些更改
,我尝试修改Alembic的Env.py.py.为了弹出用户从sqlalchemy_binds绑定的
bind_names = []
# skip 'users' bind because this database migration is handled in https://github.com/louking/members
current_app.config['SQLALCHEMY_BINDS'].pop('users')
for bind in current_app.config.get("SQLALCHEMY_BINDS"):
context.config.set_section_option(
bind, "sqlalchemy.url",
str(current_app.extensions['migrate'].db.get_engine(
current_app, bind).url).replace('%', '%%'))
bind_names.append(bind)
我,我看到了以下输出,从flask db migrate -m“通用用户数据库”
INFO [alembic.env] Migrating database <default>
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'localinterest'
INFO [alembic.autogenerate.compare] Detected added table 'localuser'
INFO [alembic.autogenerate.compare] Detected removed table 'roles_users'
INFO [alembic.autogenerate.compare] Detected removed index 'email' on 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'user'
INFO [alembic.autogenerate.compare] Detected removed index 'name' on 'role'
INFO [alembic.autogenerate.compare] Detected removed table 'role'
Generating C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\migrations\versions\cee4ca015898_common_user_database.py ... done
这正确跳过users
bind bind bind bint upgrade()
和downgrade()
功能为空。
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'cee4ca015898'
down_revision = '321e28a8aa56'
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass
编辑以显示错误而没有pop()
(venv) C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts>flask db migrate -m "common user database"
INFO [alembic.env] Migrating database <default>
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'localinterest'
INFO [alembic.autogenerate.compare] Detected added table 'localuser'
INFO [alembic.autogenerate.compare] Detected removed index 'name' on 'role'
INFO [alembic.autogenerate.compare] Detected removed table 'role'
INFO [alembic.autogenerate.compare] Detected removed index 'email' on 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'roles_users'
INFO [alembic.env] Migrating database users
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
ERROR [flask_migrate] Error: Can't locate revision identified by 'cacdee34a411'
也尝试跳过迁移
我还尝试在以下代码中跳过用户,但这也导致空升级(),
降级()
函数。
for name, rec in engines.items():
# skip 'users' bind because this database migration is handled in https://github.com/louking/members
if name == 'users': continue
logger.info("Migrating database %s" % (name or '<default>'))
context.configure(
connection=rec['connection'],
upgrade_token="%s_upgrades" % name,
downgrade_token="%s_downgrades" % name,
target_metadata=get_metadata(name),
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
context.run_migrations(engine_name=name)
Is there any way to skip a bind using flask db migrate / alembic?
I have two repos which have SQLALCHEMY_BINDS which use a common database, but otherwise the databases are different. In my case members repo uses db members
, SQLALCHEMY_BINDS={'users': usersdb_uri}
and contracts repo uses db contracts
, SQLALCHEMY_BINDS={'users': usersdb_uri}
.
I want the members repo to handle migrations of the users
db, and contracts repo to ignore it for database migration.
I'm trying to use flask-migrate to do the initial migration to add the users bind to the contracts repo, which requires some changes to the contracts
db
In the contracts repo I tried modifying alembic's env.py to pop the users bind from SQLALCHEMY_BINDS
bind_names = []
# skip 'users' bind because this database migration is handled in https://github.com/louking/members
current_app.config['SQLALCHEMY_BINDS'].pop('users')
for bind in current_app.config.get("SQLALCHEMY_BINDS"):
context.config.set_section_option(
bind, "sqlalchemy.url",
str(current_app.extensions['migrate'].db.get_engine(
current_app, bind).url).replace('%', '%%'))
bind_names.append(bind)
I see the following output from flask db migrate -m "common user database"
INFO [alembic.env] Migrating database <default>
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'localinterest'
INFO [alembic.autogenerate.compare] Detected added table 'localuser'
INFO [alembic.autogenerate.compare] Detected removed table 'roles_users'
INFO [alembic.autogenerate.compare] Detected removed index 'email' on 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'user'
INFO [alembic.autogenerate.compare] Detected removed index 'name' on 'role'
INFO [alembic.autogenerate.compare] Detected removed table 'role'
Generating C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\migrations\versions\cee4ca015898_common_user_database.py ... done
This correctly skips the users
bind, but in the revision file the upgrade()
and downgrade()
functions are empty.
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = 'cee4ca015898'
down_revision = '321e28a8aa56'
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass
Edit to show error without pop()
(venv) C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts>flask db migrate -m "common user database"
INFO [alembic.env] Migrating database <default>
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'localinterest'
INFO [alembic.autogenerate.compare] Detected added table 'localuser'
INFO [alembic.autogenerate.compare] Detected removed index 'name' on 'role'
INFO [alembic.autogenerate.compare] Detected removed table 'role'
INFO [alembic.autogenerate.compare] Detected removed index 'email' on 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'user'
INFO [alembic.autogenerate.compare] Detected removed table 'roles_users'
INFO [alembic.env] Migrating database users
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
ERROR [flask_migrate] Error: Can't locate revision identified by 'cacdee34a411'
Also tried skipping migration
I also tried skipping users within the following code, but this also results in empty upgrade()
, downgrade()
functions.
for name, rec in engines.items():
# skip 'users' bind because this database migration is handled in https://github.com/louking/members
if name == 'users': continue
logger.info("Migrating database %s" % (name or '<default>'))
context.configure(
connection=rec['connection'],
upgrade_token="%s_upgrades" % name,
downgrade_token="%s_downgrades" % name,
target_metadata=get_metadata(name),
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)
context.run_migrations(engine_name=name)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(2)
事实证明问题是因为我跳过了一步。我没有为多数据库重新创建 env.py(之前是为单个数据库创建的),而是从成员存储库复制了 env.py。
但是,我忽略了复制 script.py.mako。当我复制script.py.mako
时,修订文件已正确创建,并且flask db升级
也正常工作。
这是
bind_names = []
# skip 'users' bind because this database migration is handled in https://github.com/louking/members
current_app.config['SQLALCHEMY_BINDS'].pop('users')
for bind in current_app.config.get("SQLALCHEMY_BINDS"):
context.config.set_section_option(
bind, "sqlalchemy.url",
str(current_app.extensions['migrate'].db.get_engine(
current_app, bind).url).replace('%', '%%'))
bind_names.append(bind)
我现在在修订文件中看到的
"""common user database
Revision ID: 6f403f3025b2
Revises: 321e28a8aa56
Create Date: 2022-03-31 14:46:16.806041
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '6f403f3025b2'
down_revision = '321e28a8aa56'
branch_labels = None
depends_on = None
def upgrade(engine_name):
globals()["upgrade_%s" % engine_name]()
def downgrade(engine_name):
globals()["downgrade_%s" % engine_name]()
def upgrade_():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('localinterest',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('interest_id', sa.Integer(), nullable=True),
sa.Column('version_id', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('localuser',
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('email', sa.String(length=100), nullable=True),
sa.Column('name', sa.String(length=256), nullable=True),
sa.Column('given_name', sa.String(length=256), nullable=True),
sa.Column('active', sa.Boolean(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('interest_id', sa.Integer(), nullable=True),
sa.Column('version_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['interest_id'], ['localinterest.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.drop_table('roles_users')
op.drop_index('name', table_name='role')
op.drop_table('role')
op.drop_index('email', table_name='user')
op.drop_table('user')
# ### end Alembic commands ###
def downgrade_():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('user',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('email', mysql.VARCHAR(length=100), nullable=True),
sa.Column('name', mysql.VARCHAR(length=256), nullable=True),
sa.Column('given_name', mysql.VARCHAR(length=256), nullable=True),
sa.Column('last_login_at', mysql.DATETIME(), nullable=True),
sa.Column('current_login_at', mysql.DATETIME(), nullable=True),
sa.Column('last_login_ip', mysql.VARCHAR(length=100), nullable=True),
sa.Column('current_login_ip', mysql.VARCHAR(length=100), nullable=True),
sa.Column('login_count', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.Column('active', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True),
sa.Column('confirmed_at', mysql.DATETIME(), nullable=True),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset='utf8',
mysql_engine='InnoDB'
)
op.create_index('email', 'user', ['email'], unique=True)
op.create_table('role',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('name', mysql.VARCHAR(length=32), nullable=True),
sa.Column('description', mysql.VARCHAR(length=512), nullable=True),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset='utf8',
mysql_engine='InnoDB'
)
op.create_index('name', 'role', ['name'], unique=True)
op.create_table('roles_users',
sa.Column('id', mysql.INTEGER(display_width=11), autoincrement=True, nullable=False),
sa.Column('user_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.Column('role_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['role.id'], name='roles_users_ibfk_2'),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], name='roles_users_ibfk_1'),
sa.PrimaryKeyConstraint('id'),
mysql_default_charset='utf8',
mysql_engine='InnoDB'
)
op.drop_table('localuser')
op.drop_table('localinterest')
# ### end Alembic commands ###
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您正在执行的
pop()
调用会弄乱您的 Flask 配置。我建议您不要以这种方式进行操作,而是使用 include_object 来自 Alembic,让它跳过您不想迁移的表。The
pop()
call that you are doing is messing up your Flask configuration. Instead of going at it this way, I recommend that you use the include_object from Alembic to have it skip the tables you don't want to migrate.