Flask-Migrate产生了一个非常奇怪的错误,我无法破译。运行flask db init
和flask db migrate
运行正常,但是当我运行flask db upgrade
时,Flask-Migrate在sa.PrimaryKeyConstraint('id')
行上的TypeError上停止了。它留下了这么长的堆栈跟踪:
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> cb774072558f, empty message
Traceback (most recent call last):
File "/obfuscateddir/flask/bin/flask", line 11, in <module>
sys.exit(main())
File "/obfuscateddir/flask/lib/python3.5/site-packages/flask/cli.py", line 513, in main
cli.main(args=args, prog_name=name)
File "/obfuscateddir/flask/lib/python3.5/site-packages/flask/cli.py", line 380, in main
return AppGroup.main(self, *args, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/decorators.py", line 17, in new_func
return f(get_current_context(), *args, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/flask/cli.py", line 257, in decorator
return __ctx.invoke(f, *args, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/flask_migrate/cli.py", line 134, in upgrade
_upgrade(directory, revision, sql, tag, x_arg)
File "/obfuscateddir/flask/lib/python3.5/site-packages/flask_migrate/__init__.py", line 259, in upgrade
command.upgrade(config, revision, sql=sql, tag=tag)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/command.py", line 254, in upgrade
script.run_env()
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/script/base.py", line 425, in run_env
util.load_python_file(self.dir, 'env.py')
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/util/pyfiles.py", line 93, in load_python_file
module = load_module_py(module_id, path)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/util/compat.py", line 64, in load_module_py
module_id, path).load_module(module_id)
File "<frozen importlib._bootstrap_external>", line 388, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 809, in load_module
File "<frozen importlib._bootstrap_external>", line 668, in load_module
File "<frozen importlib._bootstrap>", line 268, in _load_module_shim
File "<frozen importlib._bootstrap>", line 693, in _load
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "migrations/env.py", line 87, in <module>
run_migrations_online()
File "migrations/env.py", line 80, in run_migrations_online
context.run_migrations()
File "<string>", line 8, in run_migrations
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/runtime/environment.py", line 836, in run_migrations
self.get_context().run_migrations(**kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/runtime/migration.py", line 330, in run_migrations
step.migration_fn(**kw)
File "/obfuscateddir/migrations/versions/cb774072558f_.py", line 59, in upgrade
sa.PrimaryKeyConstraint('id')
File "<string>", line 8, in create_table
File "<string>", line 3, in create_table
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/operations/ops.py", line 1120, in create_table
return operations.invoke(op)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/operations/base.py", line 318, in invoke
return fn(self, operation)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/operations/toimpl.py", line 101, in create_table
operations.impl.create_table(table)
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/ddl/impl.py", line 194, in create_table
self._exec(schema.CreateTable(table))
File "/obfuscateddir/flask/lib/python3.5/site-packages/alembic/ddl/impl.py", line 118, in _exec
return conn.execute(construct, *multiparams, **params)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 945, in execute
return meth(self, multiparams, params)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection
return connection._execute_ddl(self, multiparams, params)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/engine/base.py", line 996, in _execute_ddl
if not self.schema_for_object.is_default else None)
File "<string>", line 1, in <lambda>
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/elements.py", line 436, in compile
return self._compiler(dialect, bind=bind, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/ddl.py", line 26, in _compiler
return dialect.ddl_compiler(dialect, self, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 216, in __init__
self.string = self.process(self.statement, **compile_kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 242, in process
return obj._compiler_dispatch(self, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
return meth(self, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 2338, in visit_create_table
and not first_pk)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 242, in process
return obj._compiler_dispatch(self, **kwargs)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
return meth(self, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 2369, in visit_create_column
first_pk=first_pk
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/dialects/sqlite/base.py", line 863, in get_column_specification
column.type, type_expression=column)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 290, in process
return type_._compiler_dispatch(self, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
return meth(self, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 2783, in visit_string
return self.visit_VARCHAR(type_, **kw)
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 2729, in visit_VARCHAR
return self._render_string_type(type_, "VARCHAR")
File "/obfuscateddir/flask/lib/python3.5/site-packages/sqlalchemy/sql/compiler.py", line 2717, in _render_string_type
text += "(%d)" % type_.length
TypeError: %d format: a number is required, not str
有人可以更有经验解释这个错误吗?如有必要,我很乐意提供有关我的数据库架构的任何信息。另外,我在sqlalchemy_migrate中遇到了同样的错误。
更新:这是我的迁移。
"""empty message
Revision ID: cb774072558f
Revises:
Create Date: 2017-10-11 18:32:12.235047
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'cb774072558f'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('game',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('turn', sa.Integer(), nullable=True),
sa.Column('phase', sa.String(length=20), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=64), nullable=True),
sa.Column('password', sa.String(length=64), nullable=True),
sa.Column('email', sa.String(length=120), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
op.create_index(op.f('ix_user_username'), 'user', ['username'], unique=True)
op.create_table('player',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('type', sa.Integer(), nullable=True),
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('game_id', sa.Integer(), nullable=True),
sa.Column('attackpower', sa.Integer(), nullable=True),
sa.Column('defensepower', sa.Integer(), nullable=True),
sa.Column('destruction', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['game_id'], ['game.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('action',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('type', sa.String(), nullable=True),
sa.Column('origin', sa.Integer(), nullable=True),
sa.Column('dest', sa.Integer(), nullable=True),
sa.Column('start_turn', sa.Integer(), nullable=True),
sa.Column('end_turn', sa.Integer(), nullable=True),
sa.Column('count', sa.Integer(), nullable=True),
sa.Column('special', sa.String(length='500'), nullable=True),
sa.ForeignKeyConstraint(['dest'], ['player.id'], ),
sa.ForeignKeyConstraint(['origin'], ['player.id'], ),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('action')
op.drop_table('player')
op.drop_index(op.f('ix_user_username'), table_name='user')
op.drop_index(op.f('ix_user_email'), table_name='user')
op.drop_table('user')
op.drop_table('game')
# ### end Alembic commands ###
我制作了一个最小的文件来重现错误:
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
@app.route('/')
def index():
return "this isn't really part of the example"
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
password = db.Column(db.String(64))
email = db.Column(db.String(120), index=True, unique=True)
players = db.relationship('Player', backref='user', lazy=True)
#games = db.relationship('Game', backref='user', lazy='dynamic')
def __repr__(self):
return '<User %r>' % (self.username)
#is the user allowed to authenticate?
@property
def is_authenticated(self):
return True
#is the user active and unbanned?
@property
def is_active(self):
return True
#for fake users that can't login
@property
def is_anonymous(self):
return False
#return an id
def get_id(self):
try:
return unicode(self.id) #i need this for py2
except NameError:
return str(self.id)
class Game(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
players = db.relationship('Player', backref='game', lazy=True)
turn = db.Column(db.Integer)
phase = db.Column(db.String(20))
actions = db.relationship('Action', backref='game', lazy=True)
def __repr__(self):
return '<Game %r>' % (self.id)
class Player(db.Model):
id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
attackpower = db.Column(db.Integer)
defensepower = db.Column(db.Integer)
destruction = db.Column(db.Integer) #maybe constrain to >= 100?
def __repr__(self):
return '<Player %r>' % (self.id)
#is this the best way to do this?
class Action(db.Model):
id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.String)
origin = db.Column(db.Integer, db.ForeignKey('player.id'))
dest = db.Column(db.Integer, db.ForeignKey('player.id'))
start_turn = db.Column(db.Integer)
end_turn = db.Column(db.Integer)
count = db.Column(db.Integer)
special = db.Column(db.String('500')) #contains json-dumped dicts
重现:
- 将上述文本复制到名为app.py的文件中并保存在空目录中
- 使用终端,cd进入目录
-run以下(对于* nix / mac,windows可能有点不同)
virtualenv flask
source flask/bin/activate
pip install flask flask-sqlalchemy flask-migrate
export FLASK_APP=app.py
flask db init
flask db migrate
flask db upgrade
抛出错误。
答案 0 :(得分:1)
原来,最后一行:
special = db.Column(db.String('500')) #contains json-dumped dicts
抛出错误。删除500左右的引号使一切正常。