日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

完美解决Flask-Migrate使用SQLite生成自动迁移脚本的Bug

發布時間:2025/10/17 数据库 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 完美解决Flask-Migrate使用SQLite生成自动迁移脚本的Bug 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、問題描述

flask-migrate插件是對Alembic的簡單封裝,當程序使用SQLite數據庫作為backend的時候,使用 flask migrate命令生成自動遷移腳本,使用flask upgrade命令進行數據庫更新,會出現以下問題:

1、op.alter_column、op.alter_table會報錯,因為SQlite不支持替換alter column等操作。

2、對于column的一些constraint,比如:unique、foreignkey,這些操作自動腳本生成的時候無法自動探測,必須手動添加。

3、報錯:ValueError: Constraint must have a name

類似下面

Traceback (most recent call last):File "/home/openlab/flasky/venv/bin/flask", line 11, in <module>sys.exit(main())File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask/cli.py", line 894, in maincli.main(args=args, prog_name=name)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask/cli.py", line 557, in mainreturn super(FlaskGroup, self).main(*args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 697, in mainrv = self.invoke(ctx)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 1066, in invokereturn _process_result(sub_ctx.command.invoke(sub_ctx))File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 1066, in invokereturn _process_result(sub_ctx.command.invoke(sub_ctx))File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 895, in invokereturn ctx.invoke(self.callback, **ctx.params)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 535, in invokereturn callback(*args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/decorators.py", line 17, in new_funcreturn f(get_current_context(), *args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask/cli.py", line 412, in decoratorreturn __ctx.invoke(f, *args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/click/core.py", line 535, in invokereturn callback(*args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask_migrate/cli.py", line 134, in upgrade_upgrade(directory, revision, sql, tag, x_arg)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask_migrate/__init__.py", line 95, in wrappedf(*args, **kwargs)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/flask_migrate/__init__.py", line 280, in upgradecommand.upgrade(config, revision, sql=sql, tag=tag)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/command.py", line 254, in upgradescript.run_env()File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/script/base.py", line 427, in run_envutil.load_python_file(self.dir, 'env.py')File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/util/pyfiles.py", line 81, in load_python_filemodule = load_module_py(module_id, path)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/util/compat.py", line 82, in load_module_pyspec.loader.exec_module(module)File "<frozen importlib._bootstrap_external>", line 678, in exec_moduleFile "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removedFile "migrations/env.py", line 88, in <module>run_migrations_online()File "migrations/env.py", line 81, in run_migrations_onlinecontext.run_migrations()File "<string>", line 8, in run_migrationsFile "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/runtime/environment.py", line 836, in run_migrationsself.get_context().run_migrations(**kw)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/runtime/migration.py", line 330, in run_migrationsstep.migration_fn(**kw)File "/home/openlab/flasky/flasky/migrations/versions/bb9a3eb8a5fb_second_migrate.py", line 30, in upgradebatch_op.create_unique_constraint(None, ['name'])File "/usr/lib/python3.6/contextlib.py", line 88, in __exit__next(self.gen)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/operations/base.py", line 300, in batch_alter_tableimpl.flush()File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/operations/batch.py", line 76, in flushfn(*arg, **kw)File "/home/openlab/flasky/venv/lib/python3.6/site-packages/alembic/operations/batch.py", line 343, in add_constraintraise ValueError("Constraint must have a name") ValueError: Constraint must have a name

二、解決方案

步驟1:新增插件flask-migrate以及flask_sqlalchemy的初始化實參
from flask_sqlalchemy import SQLAlchemy from sqlalchemy import MetaData from flask_migrate import Migrate###初始化插件 #定義命名慣例,不需要改 naming_convention = {"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_%(table_name)s_%(column_0_name)s_%(referred_table_name)s","pk": "pk_%(table_name)s" } #初始化db,將命名慣例naming_convention傳給SQL_Alchemy,解決“ValueError: Constraint must have a name"的問題 db = SQLAlchemy(app=app,metadata=MetaData(naming_convention=naming_convention)) #使用batch操作替換普通操作,因為普通操作不支持表名,列名的改變! migrate = Migrate(app,db,render_as_batch=True)

當然,前提是安裝了flask-migrate;工廠函數初始化的方式亦然;

步驟2:生成自動化遷移腳本
>> flask db init >> flask db migrate -m 'first migrate'
步驟3:檢查生成的腳本(./migrations/versions/XXXX.py)
def upgrade():# ### commands auto generated by Alembic - please adjust! ###with op.batch_alter_table('roles', schema=None) as batch_op:batch_op.add_column(sa.Column('name2', sa.String(length=64), nullable=True))batch_op.create_unique_constraint(batch_op.f('uq_roles_name'), ['name'])batch_op.create_unique_constraint(batch_op.f('uq_roles_name1'), ['name1'])batch_op.create_unique_constraint(batch_op.f('uq_roles_name2'), ['name2'])batch_op.drop_constraint('uq_roles_id', type_='unique')with op.batch_alter_table('users', schema=None) as batch_op:batch_op.create_unique_constraint(batch_op.f('uq_users_name555'), ['name555'])# ### end Alembic commands ###def downgrade():# ### commands auto generated by Alembic - please adjust! ###with op.batch_alter_table('users', schema=None) as batch_op:batch_op.drop_constraint(batch_op.f('uq_users_name555'), type_='unique')with op.batch_alter_table('roles', schema=None) as batch_op:batch_op.create_unique_constraint('uq_roles_id', ['name1'])batch_op.drop_constraint(batch_op.f('uq_roles_name2'), type_='unique')batch_op.drop_constraint(batch_op.f('uq_roles_name1'), type_='unique')batch_op.drop_constraint(batch_op.f('uq_roles_name'), type_='unique')batch_op.drop_column('name2')
  • 自動生成的腳本可能有錯,要人工檢查。

  • ‘uq_roles_id’就是按照naming_convention生成的constraint的name,之前該位置的值為None,這是報錯 Constraint must have a name的關鍵。

  • 步驟4:執行更新操作
    >> flask db upgrade

    三、參考鏈接

    https://stackoverflow.com/questions/45527323/flask-sqlalchemy-upgrade-failing-after-updating-models-need-an-explanation-on-h

    http://alembic.zzzcomputing.com/en/latest/ops.html#alembic.operations.Operations.create_foreign_key.params.name

    http://alembic.zzzcomputing.com/en/latest/batch.html

    總結

    以上是生活随笔為你收集整理的完美解决Flask-Migrate使用SQLite生成自动迁移脚本的Bug的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。