數據庫遷移是將代碼中模型類(即表)的修改同步到數據庫中, 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