Flask项目用Flask-Migrate修改SQLite列名报错,求解决方法
Flask中修改SQLite列名报错的解决办法
问题背景
我在Flask项目里想把SQLite数据库中User表的kuota列改名为poin,但始终报错。
我的models.py代码:
class User(db.Model, UserMixin): id = db.Column(db.Integer(), primary_key=True, autoincrement=True) username = db.Column(db.String(length=30), nullable=False, unique=True) name = db.Column(db.String(length=40)) email = db.Column(db.String(length=50), nullable=False, unique=True) kuota = db.Column(db.Integer(), nullable=False, default=0) license_keys = db.relationship( 'License_Key', backref='owned_user', lazy=True)
尝试过两种方法都失败:
- 添加命名约定元数据+设置
render_as_batch=True
初始化代码:
metadata = MetaData( naming_convention={ 'pk': 'pk_%(table_name)s', 'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', 'ix': 'ix_%(table_name)s_%(column_0_name)s', 'uq': 'uq_%(table_name)s_%(column_0_name)s', 'ck': 'ck_%(table_name)s_%(constraint_name)s', } ) db = SQLAlchemy(app, metadata=metadata) migrate = Migrate(app, db, render_as_batch=True)
报错信息:
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: _alembic_tmp_user.poin [SQL: INSERT INTO _alembic_tmp_user (id, username, name, email) SELECT user.id, user.username, user.name, user.email FROM user]
- 仅设置
render_as_batch=True
生成的迁移文件:
def upgrade(): # ### commands auto generated by Alembic - please adjust! ### with op.batch_alter_table('user', schema=None) as batch_op: batch_op.add_column(sa.Column('kuota', sa.Integer(), nullable=False)) batch_op.drop_column('poin') # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### with op.batch_alter_table('user', schema=None) as batch_op: batch_op.add_column(sa.Column('poin', sa.INTEGER(), nullable=False)) batch_op.drop_column('kuota') # ### end Alembic commands ###
同样报相同错误:
NOT NULL constraint failed: _alembic_tmp_user.poin [SQL: INSERT INTO _alembic_tmp_user (id, username, name, email) SELECT user.id, user.username, user.name, user.email FROM user]
解决步骤
1. 修改models.py中的列名
先把models.py里的kuota改成poin:
class User(db.Model, UserMixin): # 其他字段不变 poin = db.Column(db.Integer(), nullable=False, default=0) # 其他代码不变
2. 手动修正自动生成的迁移文件
执行flask db migrate生成迁移文件后,不要直接执行upgrade,打开生成的迁移文件,把自动生成的错误逻辑改成正确的重命名操作:
正确的upgrade和downgrade应该是:
from alembic import op import sqlalchemy as sa def upgrade(): with op.batch_alter_table('user') as batch_op: # 把kuota重命名为poin batch_op.alter_column('kuota', new_column_name='poin') def downgrade(): with op.batch_alter_table('user') as batch_op: # 回滚,把poin改回kuota batch_op.alter_column('poin', new_column_name='kuota')
3. 执行迁移
运行flask db upgrade完成列名修改。
错误原因解释
SQLite本身不支持直接重命名列,Alembic的render_as_batch=True会通过创建临时表的方式模拟该操作。但自动生成的迁移文件逻辑错误,它尝试先加新列再删旧列,而新列poin设置了nullable=False,但临时表插入数据时没有包含该列的原有值,导致NOT NULL约束报错。手动修改迁移文件为alter_column重命名的逻辑,就能正确复用原有列的数据,避免约束问题。
内容的提问来源于stack exchange,提问作者Herahadi An
相关产品推荐
相关产品推荐

