折腾:
【已解决】Flask-Migrate升级MySQL字段时能否重命名而非删除后新建
期间,用代码:
"""update Bill, from disbursementFee to advancedFee Revision ID: d48c252c778a Revises: f96ddaedda71 Create Date: 2016-11-01 17:13:21.607969 """ # revision identifiers, used by Alembic. revision = ‘d48c252c778a’ down_revision = ‘f96ddaedda71’ from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import mysql def upgrade(): ### commands auto generated by Alembic – please adjust! ### # op.add_column(‘bills’, sa.Column(‘advancedFee’, sa.Float(), nullable=False)) op.alter_column(‘bills’, ‘disbursementFee’, new_column_name=’advancedFee’, existing_type=sa.Float(), existing_nullable=False, existing_server_default=0.0) op.create_foreign_key(None, ‘bills’, ‘tasks’, [‘errandorBillTaskId’], [‘id’]) op.create_foreign_key(None, ‘bills’, ‘tasks’, [‘initiatorBillTaskId’], [‘id’]) #op.drop_column(‘bills’, ‘disbursementFee’) op.create_foreign_key(None, ‘resources’, ‘tasks’, [‘initiatorTaskId’], [‘id’]) op.create_foreign_key(None, ‘resources’, ‘tasks’, [‘errandorTaskId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘users’, [‘errandorId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘locations’, [‘errandorEndLocationId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘locations’, [‘initiatorEndLocationId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘locations’, [‘initiatorStartLocationId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘locations’, [‘errandorStartLocationId’], [‘id’]) op.create_foreign_key(None, ‘tasks’, ‘users’, [‘initiatorId’], [‘id’]) op.create_foreign_key(None, ‘tasks_promotions’, ‘tasks’, [‘task_id’], [‘id’]) op.create_foreign_key(None, ‘tasks_promotions’, ‘promotions’, [‘promotion_id’], [‘id’]) op.create_foreign_key(None, ‘users’, ‘locations’, [‘locationId’], [‘id’]) ### end Alembic commands ### def downgrade(): ### commands auto generated by Alembic – please adjust! ### op.drop_constraint(None, ‘users’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks_promotions’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks_promotions’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘tasks’, type_=’foreignkey’) op.drop_constraint(None, ‘resources’, type_=’foreignkey’) op.drop_constraint(None, ‘resources’, type_=’foreignkey’) # op.add_column(‘bills’, sa.Column(‘disbursementFee’, mysql.FLOAT(), nullable=False)) op.drop_constraint(None, ‘bills’, type_=’foreignkey’) op.drop_constraint(None, ‘bills’, type_=’foreignkey’) # op.drop_column(‘bills’, ‘advancedFee’) op.alter_column(‘bills’, ‘advancedFee’, new_column_name=’disbursementFee’, existing_type=sa.Float(), existing_nullable=False, existing_server_default=0.0) ### end Alembic commands ### |
运行出错了:
(RunningFast) ➜ staging python db_manager.py db upgrade <div–<—————————————————————————— DEBUG in app [/root/RunningFast/staging/runningfast/app.py:86]: app=<Flask ‘runningfast.app’>, server_port=21085, api=<flask_restful.Api object at 0x7fac62372c90>, redis_store=<flask_redis.FlaskRedis object at 0x7fac6480a310>, db=<SQLAlchemy engine=’mysql://runningfast:Jiandao123@localhost/runningfast_dev’>, server_mode=staging, server_type=develop, rq=<flask_rq2.app.RQ object at 0x7fac62389110>, sockets=<flask_sockets.Sockets object at 0x7fac62389490> <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in app [/root/RunningFast/staging/runningfast/app.py:181]: API_VERSION=1.0, API_URL_PREFIX=/runningfast/api/v1.0, OPEN_API_URL_PREFIX=/runningfast/api/v1.0/open <div–<—————————————————————————— INFO [alembic.runtime.migration] Context impl MySQLImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running upgrade f96ddaedda71 -> d48c252c778a, update Bill, from disbursementFee to advancedFee Traceback (most recent call last): File "db_manager.py", line 18, in <module> manager.run() File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_script/__init__.py", line 412, in run result = self.handle(sys.argv[0], sys.argv[1:]) File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_script/__init__.py", line 383, in handle res = handle(*args, **config) File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_script/commands.py", line 216, in __call__ return self.run(*args, **kwargs) File "/root/Envs/RunningFast/lib/python2.7/site-packages/flask_migrate/__init__.py", line 239, in upgrade command.upgrade(config, revision, sql=sql, tag=tag) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/command.py", line 174, in upgrade script.run_env() File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/script/base.py", line 407, in run_env util.load_python_file(self.dir, ‘env.py’) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/util/pyfiles.py", line 93, in load_python_file module = load_module_py(module_id, path) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/util/compat.py", line 79, in load_module_py mod = imp.load_source(module_id, path, fp) 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 "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/runtime/environment.py", line 797, in run_migrations self.get_context().run_migrations(**kw) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/runtime/migration.py", line 312, in run_migrations step.migration_fn(**kw) File "/root/RunningFast/staging/migrations/versions/d48c252c778a_update_bill_from_disbursementfee_to_.py", line 25, in upgrade existing_server_default=0.0) File "<string>", line 8, in alter_column File "<string>", line 3, in alter_column File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/operations/ops.py", line 1420, in alter_column return operations.invoke(alt) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/operations/base.py", line 318, in invoke return fn(self, operation) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/operations/toimpl.py", line 53, in alter_column **operation.kw File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 48, in alter_column else existing_autoincrement File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/impl.py", line 118, in _exec return conn.execute(construct, *multiparams, **params) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 945, in execute return meth(self, multiparams, params) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection return connection._execute_ddl(self, multiparams, params) File "/root/Envs/RunningFast/lib/python2.7/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 "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 436, in compile return self._compiler(dialect, bind=bind, **kw) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 26, in _compiler return dialect.ddl_compiler(dialect, self, **kw) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 216, in __init__ self.string = self.process(self.statement, **compile_kwargs) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 242, in process return obj._compiler_dispatch(self, **kwargs) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/ext/compiler.py", line 435, in <lambda> lambda *arg, **kw: existing(*arg, **kw)) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/ext/compiler.py", line 474, in __call__ return fn(element, compiler, **kw) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 274, in _mysql_change_column autoincrement=element.autoincrement File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 295, in _mysql_colspec spec += " DEFAULT %s" % _render_value(compiler, server_default) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 283, in _render_value return compiler.sql_compiler.process(expr) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 242, in process return obj._compiler_dispatch(self, **kwargs) AttributeError: ‘float’ object has no attribute ‘_compiler_dispatch’ |
1.搜:
alembic AttributeError float object has no attribute _compiler_dispatch
alembic AttributeError float no _compiler_dispatch
flask – AttributeError: ‘int’ object has no attribute ‘_compiler_dispatch’ – Stack Overflow
尝试把:
sa.Float()
改为:
sa.Float
试试。
因为记得之前代Flask的SQLAlchemy代码中,也是这么写的:
advancedFee = db.Column(db.Float, nullable=False, default = 0.0) |
结果问题依旧。
2.看到错误中有:
spec += " DEFAULT %s" % _render_value(compiler, server_default)
感觉是和
existing_server_default
有关系,所以去掉:
op.alter_column(‘bills’, ‘disbursementFee’, new_column_name=’advancedFee’, existing_type=sa.Float, existing_nullable=False) op.alter_column(‘bills’, ‘advancedFee’, new_column_name=’disbursementFee’, existing_type=sa.Float, existing_nullable=False) |
结果:
就升级成功了:
(RunningFast) ➜ staging python db_manager.py db upgrade <div–<—————————————————————————— DEBUG in app [/root/RunningFast/staging/runningfast/app.py:86]: app=<Flask ‘runningfast.app’>, server_port=21085, api=<flask_restful.Api object at 0x7fe343f7ac90>, redis_store=<flask_redis.FlaskRedis object at 0x7fe346412310>, db=<SQLAlchemy engine=’mysql://runningfast:Jiandao123@localhost/runningfast_dev’>, server_mode=staging, server_type=develop, rq=<flask_rq2.app.RQ object at 0x7fe343f91110>, sockets=<flask_sockets.Sockets object at 0x7fe343f91490> <div–<—————————————————————————— <div–<—————————————————————————— DEBUG in app [/root/RunningFast/staging/runningfast/app.py:181]: API_VERSION=1.0, API_URL_PREFIX=/runningfast/api/v1.0, OPEN_API_URL_PREFIX=/runningfast/api/v1.0/open <div–<—————————————————————————— INFO [alembic.runtime.migration] Context impl MySQLImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running upgrade f96ddaedda71 -> d48c252c778a, update Bill, from disbursementFee to advancedFee |
【总结】
此处,虽然官网文档:
Operation Reference — Alembic 0.8.9 documentation
说是最好三个参数如果没有改变,最好都传递,结果传递了existing_server_default,就会导致此处的错误:
File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 274, in _mysql_change_column autoincrement=element.autoincrement File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 295, in _mysql_colspec spec += " DEFAULT %s" % _render_value(compiler, server_default) File "/root/Envs/RunningFast/lib/python2.7/site-packages/alembic/ddl/mysql.py", line 283, in _render_value return compiler.sql_compiler.process(expr) File "/root/Envs/RunningFast/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 242, in process return obj._compiler_dispatch(self, **kwargs) AttributeError: ‘float’ object has no attribute ‘_compiler_dispatch’ |
解决办法是:
不要传递existing_server_default
变成:
from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import mysql def upgrade(): ### commands auto generated by Alembic – please adjust! ### # op.add_column(‘bills’, sa.Column(‘advancedFee’, sa.Float(), nullable=False)) op.alter_column(‘bills’, ‘disbursementFee’, new_column_name=’advancedFee’, existing_type=sa.Float, existing_nullable=False) #op.drop_column(‘bills’, ‘disbursementFee’) ### end Alembic commands ### def downgrade(): ### commands auto generated by Alembic – please adjust! ### # op.add_column(‘bills’, sa.Column(‘disbursementFee’, mysql.FLOAT(), nullable=False)) # op.drop_column(‘bills’, ‘advancedFee’) op.alter_column(‘bills’, ‘advancedFee’, new_column_name=’disbursementFee’, existing_type=sa.Float, existing_nullable=False) ### end Alembic commands ### |
就可以了。
另外,对于此处的:
sa.Float()
还是:
sa.Float
好像都是可以的。
转载请注明:在路上 » 【已解决】Flask-Migrate内部利用Alembic中升级数据库时出错:AttributeError float object has no attribute _compiler_dispatch