【发布时间】:2020-09-03 22:19:28
【问题描述】:
我正在尝试升级数据库,但迁移脚本不断创建无外键约束。我试图从用户表中删除一个名为 kiosk 的布尔值,同时添加与 backref 的 kiosk 的 kiosk_id 表的多对一关系。如果我执行一个脚本来删除 kiosk 布尔值,它会很好地删除它,但它拒绝建立从用户表到 kiosk_id 表的多对一关系。
这里是迁移脚本
"""
Revision ID: f76e23eb53f4
Revises: 3354e9f7076a
Create Date: 2020-09-02 20:13:22.217435
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'f76e23eb53f4'
down_revision = '3354e9f7076a'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('kiosk_id',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=128), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('kiosk_response_id',
sa.Column('id', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('kiosk_question',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('question', sa.String(length=256), nullable=True),
sa.Column('kiosk_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['kiosk_id'], ['kiosk_id.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('kiosk_response',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('response', sa.String(length=256), nullable=False),
sa.Column('response_id', sa.Integer(), nullable=True),
sa.Column('question_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['question_id'], ['kiosk_question.id'], ),
sa.ForeignKeyConstraint(['response_id'], ['kiosk_response_id.id'], ),
sa.PrimaryKeyConstraint('id')
)
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.add_column(sa.Column('kiosk_id', sa.Integer(), nullable=True))
#THIS IS THE PROBLEM
batch_op.create_foreign_key(None, 'kiosk_id', ['kiosk_id'], ['id'])
#HERE IS THE ISSUE
batch_op.drop_column('kiosk')
# ### 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('kiosk', sa.BOOLEAN(), nullable=True))
batch_op.drop_constraint(None, type_='foreignkey')
batch_op.drop_column('kiosk_id')
op.drop_table('kiosk_response')
op.drop_table('kiosk_question')
op.drop_table('kiosk_response_id')
op.drop_table('kiosk_id')
# ### end Alembic commands ###
我正在尝试添加以下关系。
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), index=True, unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
#Dropping this boolean and replacing with a backref from Kiosk_ID
#kiosk=db.Column(db.Boolean, default=False)
#Adding this foriegn key for a 1 to many from kiosk_id
kiosk_id=db.Column(db.Integer, db.ForeignKey('kiosk_id.id'))
def __repr__(self): # pragma: no cover
return '<user> %r' % (self.username)
class Kiosk_ID(db.Model):
__tablename__='kiosk_id'
id=db.Column(db.Integer, primary_key=True)
name=db.Column(db.String(128), nullable=False)
users=db.relationship('User', backref='kiosk')
questions=db.relationship('Kiosk_Question', backref='kiosk')
def __repr__(self): # pragma: no cover
return '<Kiosk_ID: > %r' % (self.name)
class Kiosk_Question(db.Model):
__tablename__='kiosk_question'
id=db.Column(db.Integer, primary_key=True)
question=db.Column(db.String(256))
kiosk_id=db.Column(db.Integer, db.ForeignKey('kiosk_id.id'))
responses=db.relationship('Kiosk_Response', backref='question')
def __repr__(self): # pragma: no cover
return '<Question: > %r' % (self.question)
class Kiosk_Response_ID(db.Model):
__tablename__='kiosk_response_id'
id=db.Column(db.Integer, primary_key=True)
responses=db.relationship('Kiosk_Response', backref='kiosk_response')
def __repr__(self): # pragma: no cover
return '<Response ID: > %r' % (self.id)
class Kiosk_Response(db.Model):
__tablename__='kiosk_response'
id=db.Column(db.Integer, primary_key=True)
response=db.Column(db.String(256), nullable=False)
response_id=db.Column(db.Integer, db.ForeignKey('kiosk_response_id.id'))
question_id=db.Column(db.Integer, db.ForeignKey('kiosk_question.id'))
def __repr__(self): # pragma: no cover
return '<Response: > %r' % (self.response)
我在删除 kiosk 布尔列时遇到了问题,但通过在我的 init 中添加“rend_as_batch=True”来修复它。我认为它不相关,但我无法弄清楚为什么这个错误不断出现,而我大约在同一时间进行了更改。
def create_app(config_class=Config):
...
#Fixes flask db upgrade to allow deleting columns
with app.app_context():
if db.engine.url.drivername == 'sqlite':
migrate.init_app(app, db, render_as_batch=True)
else:
migrate.init_app(app, db)
...
这是我在运行 flask db migrate 后运行 flask db upgrade 时发生的情况。
INFO [alembic.runtime.migration] Running upgrade 3354e9f7076a -> 3433e257dcb1, empty message
Traceback (most recent call last):
File "/home/bob/cat/env/bin/flask", line 8, in <module>
sys.exit(main())
File "/home/bob/cat/env/lib/python3.6/site-packages/flask/cli.py", line 967, in main
cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None)
File "/home/bob/cat/env/lib/python3.6/site-packages/flask/cli.py", line 586, in main
return super(FlaskGroup, self).main(*args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/click/decorators.py", line 21, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/flask/cli.py", line 426, in decorator
return __ctx.invoke(f, *args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/flask_migrate/cli.py", line 134, in upgrade
_upgrade(directory, revision, sql, tag, x_arg)
File "/home/bob/cat/env/lib/python3.6/site-packages/flask_migrate/__init__.py", line 96, in wrapped
f(*args, **kwargs)
File "/home/bob/cat/env/lib/python3.6/site-packages/flask_migrate/__init__.py", line 271, in upgrade
command.upgrade(config, revision, sql=sql, tag=tag)
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/command.py", line 298, in upgrade
script.run_env()
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/script/base.py", line 489, in run_env
util.load_python_file(self.dir, "env.py")
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/util/pyfiles.py", line 98, in load_python_file
module = load_module_py(module_id, path)
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/util/compat.py", line 184, in load_module_py
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 678, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "migrations/env.py", line 96, in <module>
run_migrations_online()
File "migrations/env.py", line 90, in run_migrations_online
context.run_migrations()
File "<string>", line 8, in run_migrations
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/runtime/environment.py", line 846, in run_migrations
self.get_context().run_migrations(**kw)
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/runtime/migration.py", line 520, in run_migrations
step.migration_fn(**kw)
File "/home/bob/cat/migrations/versions/3433e257dcb1_.py", line 49, in upgrade
batch_op.drop_column('kiosk')
File "/usr/lib/python3.6/contextlib.py", line 88, in __exit__
next(self.gen)
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/operations/base.py", line 354, in batch_alter_table
impl.flush()
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/operations/batch.py", line 114, in flush
fn(*arg, **kw)
File "/home/bob/cat/env/lib/python3.6/site-packages/alembic/operations/batch.py", line 497, in add_constraint
raise ValueError("Constraint must have a name")
ValueError: Constraint must have a name
我修好了,有点。我更改了以下蒸馏线:
batch_op.create_foreign_key(None, 'kiosk_id', ['kiosk_id'], ['id'])
到这里
batch_op.create_foreign_key('None', 'kiosk_id', ['kiosk_id'], ['id'])
我给它取什么名字有关系吗? ('None') 我想以后可能会导致问题,但我不确定为什么它首先要求我命名关系。
【问题讨论】:
-
create_foreign_key()的第一个参数是约束名称。见alembic.sqlalchemy.org/en/latest/…。您是否尝试过在那里设置名称而不是传递None? -
我尝试命名它,但它不起作用。如果我核对 app.db 和迁移脚本并重新运行 flask db init -> flask db migrate -> flask db upgrade 那么它工作正常。我只是希望我可以让它从这里迁移而不会丢失数据。有没有可能因为我做了一个烧瓶数据库戳头来修复另一个错误,而它做了一些奇怪的事情?
-
您需要更具体。设置名称后哪个命令不起作用?
-
当我运行 flask db migrate 时,它执行得很好,但它会将 user.kiosk_id 的外键名称设置为 None。当我运行flask db upgrade时,它会抛出一个错误,提示用户.kiosk_id不允许使用None。如果我手动将脚本中的名称更改为某个名称,它仍然会给我一个错误。
-
抱歉,如果您不提供详细信息,我将无能为力。请问是什么错误?
标签: python flask flask-sqlalchemy flask-migrate