【已解决】Flask-Migrate内部利用Alembic中升级数据库时出错:AttributeError float object has no attribute _compiler_dispatch

折腾:

【已解决】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

好像都是可以的。



发表评论

电子邮件地址不会被公开。 必填项已用*标注

无觅相关文章插件,快速提升流量