数据库迁移是将代码中模型类(即表)的修改同步到数据库中, flask-sqlalchemy的模型类一旦使用create_all()映射到数据库中后,对这个模型类的修改(例如添加了一个新的字段)就不会再映射到数据库中了,这时候想要在数据库中获得新的表就须要删掉从新映射一次,但是这样作的话原先表中的数据也没了,这确定是不行的,数据库中的数据怎么能随便删呢,而数据库迁移操做就完美解决了这个问题。python
就像ORM操做有sqlalchemy和flask-sqlalchemy同样,数据库迁移也有alembic和flask-migrate,alembic是全部Python程序均可以用的三方库,而flask-migrate则是flask专用的,可是它们的用法都是类似的。mysql
flask中若是再配合另外一个三方库flask-script就能更加方便的管理数据库了,flask-script能让Python中的函数能以命令的形式在DOS窗口中执行,让咱们更加方便地管理项目,固然也包括数据库操做。sql
1、flask-script使用数据库
安装:pip install flask-scriptflask
1. 主文件:通常用于启动flask-script的Manager,能够经过主文件调用全部的函数(必须是被[Manager_obj].command装饰的函数才能被调用,并且通常不会全部的函数都定义在主文件中),好比新建并写好一个简单的py文件“manage.py”,而后就能够在DOS中使用命令“python manage.py runserver”调用了:app
from flask_script import Manager from flask_script_migrate_demo import app # 实例化Manager,app为Flask实例对象,能够从其余文件导入 manage = Manager(app) # 使用此装饰器装饰的函数才能在DOS中调用 @manage.command def runserver(): # ... # print('The server has been started!') if __name__ == '__main__': manage.run() # 启动Manager
2.命令传参:使用@[Manager_obj].option()定义命令的参数,有多少个参数就须要多少个装饰器,且他们之间的顺序不能乱ide
# 装饰器@manager.option:有多少个参数就使用多少个manager.option装饰器,且顺序要与函数一致(从上到下) # 命令简写:-u是命令--username的简写,其实真正的命令是--username,就是说这两个命令均可以使用 # 命令全称:dest是用于映射函数的参数名称 # 使用示例:DOS中可使用以下命令:python manage.py add_user -u Jason -a 18 @manager.option('-u', '--username', dest='username') @manager.option('-a', '--age', dest='age') def add_user(username, age): print("用户名:%s,年龄:%s" % (username, age))
2.子文件(子命令):当flask_script管理的命令太多的时候,就须要归类放到不一样的子文件中,且子文件通常用于放置操做函数,而后经过主文件来调用,须要注意是子文件中的函数一样须要装饰器“[Manager_obj].command”,不过子文件中的Manager实例化不须要app(Flask对象)了,同时在主文件中须要使用“[Manager_obj].add_command('[sub_manager_obj_name]', [sub_manager_obj])”将子文件中的Manager添加到主文件中,“sub_manager_obj_name”为子文件中Manager对象的别名(DOS调用的就是它),以下代码在DOS中使用命令“python manage.py db db_init”调用便可:函数
主文件manage.py和子文件db_scripts.py:url
from flask_script import Manager from flask_script_migrate_demo import app from db_scripts import DBManage manage = Manager(app) # 将子文件db_scripts的Manager对象DBManage导入,别名db_manage将用于DOS调用 manage.add_command('db_manage', DBManage) if __name__ == '__main__': manage.run() # 启动Manager
from flask_script import Manager # 须要APP(Flask对象)来实例化 DBManage = Manager() # 一样须要command装饰器 @DBManage.command def db_init(): # ... # print('The database has been initialized successfully!')
2、alembic使用spa
安装:pip install alembic
迁移过程:定义模型类 -> 生成迁移脚本 -> 映射更新到数据库
注意:使用alembic时须要先CD到项目根目录下,而后再使用alembic
准备操做:
from sqlalchemy import Column, String, Integer from sqlalchemy.ext.declarative import declarative_base USERNAME = 'root' PASSWORD = '123456' HOST = '127.0.0.1' # 本机 PORT = '3306' # MySQL默认端口 DATABASE = 'alembic_demo' # 数据库名 # 数据库链接字符串 DB_URI = 'mysql+pymysql://{username}:{password}@{host}:{port}/{database}?charset=utf8'.format( username=USERNAME, password=PASSWORD, host=HOST, port=PORT, database=DATABASE ) # 模型类基类 Base = declarative_base(DB_URI) class User(Base): """简单模型类""" __tablename__ = 'user' id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(50), nullable=False) age = Column(Integer, nullable=False, default=18)
生成迁移脚本:alembic revision --autogenerate -m "[message]"。其中message是本身定义的这次提交/更新的信息,方便之后查看和问题跟踪。而且执行成功后会在[alembic_name]/versions下生成一个对应版本的脚本迁移文件
映射更新数据库:alembic upgrade head。head表示最新迁移脚本的版本号,也能够不用head,而使用指定脚本的版本号,迁移脚本中revision的值即为该脚本对应的版本号。同时第一次upgrade时会在数据库中建立一张名为alembic_version的表,此表只有一列一行数据,即当前数据库的版本号。
alembic经常使用命令和参数:
常见错误和解决方案:
错误1: Target database is not up to date
缘由:数据库的版本(current)和最新迁移脚本(head)的版本不一致
解决方案:使用alembic upgrade head将数据库更新为最新的版本便可
错误2: Can't locate revision identified by 'xxxxx'
缘由:数据库中的版本号没有在迁移脚本中找到对应的版本(或许对应的迁移脚本文件被删了)
解决方案:能够先删除alembic_version中的版本数据,再upgrade(这时候可能须要将全部的迁移脚本中的upgrade函数pass掉),这里的解决方案不肯定,知道缘由后灵活操做就好了。
3、flask-migrate使用
安装:pip install flask-migrate
1. 做用:通常数据库模型类都是使用专门的py来定义存放的,好比“models.py”,当需求变化时,可能这些Model都已经映射到数据库中了,再想要修改时(好比新增长一列),若是没有其余插件,就只能删除数据库中的表,再从新生成了,显然这是不实用的,因此flask-migrate就显得很是有用了,它能够将代码中对数据库的修改同步更新(迁移操做)到数据库中。
2. 依赖插件:flask-migrate插件是依赖于flask-script的,因此要使用flask-migrate,就须要先装好flask-script。
3. 基本使用(db为本身定义的flask-script子命令,见示例代码):
from flask_script import Manager from flask_script_migrate_demo import app from flask_migrate import Migrate, MigrateCommand from extends import db # db为SQLAlchemy对象 from models import User # User为db.Model的子类,即模型类,其余未导入的模型类就不能映射到数据库了 manager = Manager(app)
# 绑定app和db到flask_migrate中 Migrate(app, db) # 为manager取一个别名,并做为子命令使用 manager.add_command('db', MigrateCommand) if __name__ == '__main__': manager.run() # 启动Manager