zoukankan      html  css  js  c++  java
  • flask 使用Flask-Migrate迁移数据库(创建迁移环境、生成迁移脚本、更新数据库) --

    使用Flask-Migrate迁移数据库

    在开发时,以删除表再重建的方式更新数据库简单直接,但明显的缺陷是会丢掉数据库中的所有数据。在生产环境下,没有人想把数据都删除掉,这时需要使用数据库迁移工具来完成这个工作。SQLAlchemy的开发者Michael Bayer写了一个数据库迁移工作—Alembic来帮助我们实现数据库的迁移,数据库迁移工具可以在不破坏数据的情况下更新数据库表的结构。蒸馏器(Alembic)是炼金术士最重要的工具,要学习SQL炼金术(SQLAlchemy),当然要掌握蒸馏器的使用。

    扩展Flask-Migrate继承了Alembic,提供了一些flask命令来简化迁移工作,我们将使用它来迁移数据库。Flask-Migrate及其依赖(主要是Alembic)可以使用pipenv安装:

    (Lenovo-ezd1lI9Y) C:UsersLenovo>pipenv install flask-migrate

     

    在程序中,我们实例化Flask-Migrate提供的Migrate类,进行初始化操作:

    from flask import Flask, render_template, flash, url_for, redirect
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    migrate = Migrate(app, db)  # 在db对象创建后调用
     

    实例化Migrate类时,除了传入程序app,还需要传入实例化Flask-SQLAlchemy提供的SQLAlchemy类创建的db对象作为第二个参数。

    1、创建迁移环境--flask db init

    在开始迁移数据之前,需要先使用下面的命令创建一个迁移环境:

    (Lenovo-ezd1lI9Y) D:flaskFLASK_PRACTICEDataBase>flask db init
    Creating directory D:flaskFLASK_PRACTICEDataBasemigrations ... done
    Creating directory D:flaskFLASK_PRACTICEDataBasemigrationsversions ... done
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsalembic.ini ... done
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsenv.py ... done
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsenv.pyc ... done
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsREADME ... done
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsscript.py.mako ... done
    Please edit configuration/connection/logging settings in 'D:\flask\FLASK_PRACTICE\DataBase\migrations\alembic.ini' before proceeding.

    Flask-Migrate提供了一个命令集,使用db作为命令集名称,它提供的命令都以flask db开头。你可以在命令行中输入flask—help查看所有可用的命令和说明。

    (Lenovo-ezd1lI9Y) D:flaskFLASK_PRACTICEDataBase>flask db --help
    Usage: flask db [OPTIONS] COMMAND [ARGS]...
    
      Perform database migrations.
    
    Options:
      --help  Show this message and exit.
    
    Commands:
      branches   Show current branch points
      current    Display the current revision for each database.
      downgrade  Revert to a previous version
      edit       Edit a revision file
      heads      Show current available heads in the script directory
      history    List changeset scripts in chronological order.
      init       Creates a new migration repository.
      merge      Merge two revisions together, creating a new revision file
      migrate    Autogenerate a new revision file (Alias for 'revision...
      revision   Create a new revision file.
      show       Show the revision denoted by the given symbol.
      stamp      'stamp' the revision table with the given revision; don't run...
      upgrade    Upgrade to a later version

    迁移环境只需要创建一次。这会在你的项目根目录下创建一个migrations文件夹其中包含了自动生成的配置文件和迁移版本文件夹。

    2、生成迁移脚本--flask db migrate -m "add note timestamp"

    使用migrate子命令可以自动生成迁移脚本:

    (Lenovo-ezd1lI9Y) D:flaskFLASK_PRACTICEDataBase>flask db migrate -m "add note timestamp"
    INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
    INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    INFO  [alembic.autogenerate.compare] Detected removed table u'draft'
    INFO  [alembic.autogenerate.compare] Detected removed table u'post'
    INFO  [alembic.autogenerate.compare] Detected removed table u'comment'
    Generating D:flaskFLASK_PRACTICEDataBasemigrationsversionscdd9d12762fc_add_note_timestamp.py ... done

    这条命令可以简单理解为在flask里对数据库(db)进行迁移(migrate)。-m选项用来添加迁移备注信息。从上面的输出信息我们可以看到,Alembic检测出了模型变化:表note新加了一个timestamp列,并且相应生成了一个迁移脚本cdd9d12762fc_add_note_timestamp.py:

    """add note timestamp
    
    Revision ID: 7f3dae8cae4d
    Revises: 
    Create Date: 2019-04-01 21:56:32.469000
    
    """
    from alembic import op
    import sqlalchemy as sa
    
    
    # revision identifiers, used by Alembic.
    revision = '7f3dae8cae4d'
    down_revision = None
    branch_labels = None
    depends_on = None
    
    
    def upgrade():
        # ### commands auto generated by Alembic - please adjust! ###
        op.drop_table('draft')
        op.drop_table('post')
        op.drop_table('comment')
        op.add_column('note', sa.Column('timeStamp', sa.String(length=70), nullable=True))
        op.create_unique_constraint(None, 'note', ['timeStamp'])
        # ### end Alembic commands ###
    
    
    def downgrade():
        # ### commands auto generated by Alembic - please adjust! ###
        op.drop_constraint(None, 'note', type_='unique')
        op.drop_column('note', 'timeStamp')
        op.create_table('comment',
        sa.Column('id', sa.INTEGER(), nullable=False),
        sa.Column('body', sa.TEXT(), nullable=True),
        sa.Column('post_id', sa.INTEGER(), nullable=True),
        sa.ForeignKeyConstraint(['post_id'], [u'post.id'], ),
        sa.PrimaryKeyConstraint('id')
        )
        op.create_table('post',
        sa.Column('id', sa.INTEGER(), nullable=False),
        sa.Column('title', sa.VARCHAR(length=50), nullable=True),
        sa.Column('body', sa.TEXT(), nullable=True),
        sa.PrimaryKeyConstraint('id')
        )
        op.create_table('draft',
        sa.Column('id', sa.INTEGER(), nullable=False),
        sa.Column('body', sa.TEXT(), nullable=True),
        sa.Column('edit_time', sa.INTEGER(), nullable=True),
        sa.PrimaryKeyConstraint('id')
        )
        # ### end Alembic commands ###
     

    从上面的代码可以看出,迁移脚本主要包含了两个函数:upgrate()函数用来将改动应用到数据库,函数中包含了向表中添加timestamp字段的命令,而downgrade()函数用来撤消改动,包含了删除timestamp字段的命令。

    就像这两个函数中的注释所说的,迁移命令是有Alembic自动生成的,其中可能包含错误,所以有必要在生成后检查一下。

    因为每一次迁移都会生成新的迁移脚本,而且Alemic为每一次迁移都生成了修订版本(revision)ID,所以数据库可以恢复到修改历史中的任一点。正因如此,迁移环境中的文件也要纳入版本控制。

    有些复杂的错误无法实现自动迁移,这时可以使用revision命令手动创建迁移脚本。这同样会生成一个迁移脚本,不过脚本中的upgrade()和downgrade()函数都是空的。你需要使用Alembic提供的Operations对象指令在这两个函数中实现具体操作,具体可以访问Alembic官方文档查看。

    3、更新数据库--flask db upgrade

    生成了迁移脚本后,使用upgrade子命令即可更新数据库:

    (Lenovo-ezd1lI9Y) D:flaskFLASK_PRACTICEDataBase>flask db upgrade
    INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
    INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    INFO  [alembic.runtime.migration] Running upgrade  -> 7f3dae8cae4d, add note timestamp
    ERROR [root] Error: No support for ALTER of constraints in SQLite dialect

    如果还没有创建数据库和表,这个命令会自动创建,如果已经创建,则会在不损坏数据的前提下执行更新。

    从客户端可以看到note表新增加了一个timestamp字段

    如果你想回滚迁移,那么可以使用downgrade命令(降级),它会撤销最后一次迁移在数据库中的改动,这在开发时非常有用。比如,当执行upgrade命令后发现某些地方出错了,这时就可以执行flask db downgrade命令进行回滚,删除对应的迁移脚本,重新生成迁移脚本后再进行更新(upgrade)。


    SQLite迁移问题:flask db downgrade 报错
    (Lenovo-ezd1lI9Y) D:flaskFLASK_PRACTICEDataBase>flask db downgrade 5e87b4da6187
    INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
    INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    ERROR [root] Error: Destination 5e87b4da6187 is not a valid downgrade target from current head(s)

    是因为sqlite不支持alter机制的原因

    开发时是否需要迁移?

    在生产环境下,当对数据库结构进行修改后,进行数据库迁移是必要的。因为你不想损坏任何数据,在生成自动迁移脚本之后,执行更新之前,对迁移脚本进行检查,甚至是使用备份的数据库进行迁移测试,都是有必要的。

    在开发环境中,你可以按需要选择是否进行数据库迁移,对于大多数程序来说,可以在开发时使用虚拟数据生成工具来生成虚拟数据,从而避免手动创建记录进行测试,这样每次更改表结构时,可以直接清楚后重新生成,然后生成测试数据,这要比执行一次迁移简单的多(后续会学到通过一个命令完成所有工作),除非生成虚拟数据耗费的时间过长。

    另外,在本地本地开发时通常使用SQLite作为数据库引擎。SQLite不支持ALTER语句,而这正是迁移工具依赖的工作机制,也就是说,当SQLite数据库的字段删除或修改后,我们没法直接使用迁移工具进行更新,你需要手动添加迁移代码进行迁移。在开发中,修改和删除列是很常见的行为,手动操作迁移会花费太多时间。

    对于SQLite,迁移工具一般使用”move and copy”的工作流(创建新表、迁移数据、删除旧表)达到类似的效果。

    如果希望让生产环境的部署更搞笑,则应该尽可能让开发环境和生产环境保持一致。这时应该考虑直接在本地使用MySQL或其他的DBMS,然后设置迁移环境。

  • 相关阅读:
    JavaScript
    94.Binary Tree Inorder Traversal
    144.Binary Tree Preorder Traversal
    106.Construct Binary Tree from Inorder and Postorder Traversal
    105.Construct Binary Tree from Preorder and Inorder Traversal
    90.Subsets II
    78.Subsets
    83.Merge Sorted Array
    80.Remove Duplicates from Sorted Array II
    79.Word Search
  • 原文地址:https://www.cnblogs.com/xiaxiaoxu/p/10652054.html
Copyright © 2011-2022 走看看