Flask學習筆記:數據庫遷移操做flask-script+alembic/flask-migrate

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

  準備操做: 

  1. alembic init [alembic_name]:在DOS中(項目跟目錄)執行此命令,初始化建立一個alembic遷移倉庫,通常名稱能夠就叫alembic,以便識別
  2. sqlalchemy.url:在alembic.ini文件中修改sqlalchemy.url的值爲數據庫鏈接字符串便可,例如sqlalchemy.url = mysql+pymysql://root:123456@localhost/alembic_demo?charset=utf8,若是是本機的話HOST的值就寫localhost就行,其中alembic_demo爲數據庫名稱
  3. target_metadata:在建立好的[alembic_name]文件夾下的env.py中給target_metadata賦值爲對應的metadata,例如:target_metadata = alembic_demo.Base.metadata。
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經常使用命令和參數:

  • init: 建立一個alembic倉庫
  • revision: 建立一個新的版本號
  • --autogenerate: 自動將當前的模型的修改生成遷移腳本
  • -m: 定義本次遷移的描述
  • upgrade: 將指定版本號的遷移腳本映射到數據庫中(更新),即執行遷移腳本中的upgrade函數
  • downgrade: 將指定版本的遷移腳本映射到數據庫中(回退),即執行遷移腳本中的downgrade函數
  • head: 表明的最新遷移腳本的版本號
  • heads: 查看最新的版本號(head)
  • history: 查看全部的遷移信息(版本號變化及每次遷移時-m參數定義的消息)
  • current: 查看當前的版本號(數據庫)
  • 注:映射數據庫時(更新或回退)會執行兩個版本間的全部遷移腳本

  常見錯誤和解決方案:

  錯誤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子命令,見示例代碼):

    • 初始化:Python manage.py db init
    • 生成遷移腳本:Python manage.py db migrate
    • 映射到數據庫中:Python manage.py db upgrade
    • 查看命令:查看全部的migrate命令Python manage.py db --help
    • 使用示例:第一次執行manage.py的時候,須要依次使用命令「python manage.py db init」(初始化遷移環境)、「python manage.py db migrate」(生成對應的遷移文件)和「python manage.py db upgrade」(將遷移文件同步更新到數據庫中)來完成數據庫的映射,當以後你的model類中有改變時,只須要依次運行後面兩個命令「migrate」和「upgrade」便可對數據庫進行同步更新。其中「manage.py」和「db」是自定義的名稱,見以下代碼:
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
相關文章
相關標籤/搜索