1.Flask-Migrate的使用
flask-migrate相關配置:
1 from Application import app 2 from common.models.model import db 3 from flask_migrate import Migrate, MigrateCommand 4 5 migrate = Migrate(app, db, render_as_batch=True, compare_type=True, compare_server_default=True) 6 manager.add_command('db', MigrateCommand) 7 manager.add_command('runserver', Server(host='0.0.0.0'))
8 if __name__ == '__main__':
9 manager.run()
flask-migrate
相關的命令:
python manage.py db init
:初始化一個遷移腳本的環境,只需要執行一次。python manage.py db migrate
:將模型生成遷移文件,只要模型更改了,就需要執行一遍這個命令。python manage.py db upgrade
:將遷移文件真正的映射到數據庫中。每次運行了migrate
命令后,就記得要運行這個命令。
2. 常見"坑"的解決辦法
第一坑:安裝最新版本的flask-migrate插件
首先安裝flask-migrate,如果直接pip install flask-migrate安裝,默認是安裝的是最新版本,這時候你會發現,最新版本和flask的版本會有沖突,導入MigrateCommand時報錯。
解決辦法:
指定版本安裝 ,經過測試:Flask==1.1.2 flask-migrate==2.7.0不會出現問題。
安裝完flask-migrate后,為了更好的使用它,我們還得安裝另一個很實用的插件flask-script,這是一個項目管理類的插件,可以自定義命令去管理我們的項目。同樣的該插件的最新版本,也會和高版本的flask產生沖突,經過測試Flask==1.1.2不會出現問題。
所以說,如果要使用以上兩個插件,Flask版本不能太高,否則會出現兼容問題。
第二坑:當使用sqlite時的alter
這次坑的是sqlite,主要是sqlite自己太坑。它不支持drop列,不支持完整的數據庫alter語句功能等等。當使用sqlite做migrate和upgrade以及downgrade時,模型有字段的減少或者約束的減少,會報錯:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "DROP": syntax error [SQL: ALTER TABLE account DROP COLUMN name]
解決方法:
初始化Migrate對象時可以設置其提交類型為批處理 migrate = Migrate(db=db, render_as_batch=True)
以批處理的方式做表結構修改sqlite是支持的,但是批處理本身有安全性的問題。批處理提升了效率,但是喪失了原子性,其中某些sql語句出錯我們並不能直接感知到。所以盡量對migrate生成的腳本進行人工檢查吧,不怕一萬就怕萬一。
第三坑:字段長度等屬性的修改
FlaskMigrate默認對字段屬性的變動是不做檢查的。所以當發現256長的A字段的不足以支撐功能,我們需要把它變成1000,修改代碼后做migrate會發現提示No changes in schema detected.
解決方法:
上面提到的alembic的源碼的EnvironmentContext類內的configure方法里有個sqlalchemy_module_prefix參數旁邊還有一些其他的小參數,這次沒有坑爹,比較給力,還是貼一下源碼吧:

1 def configure( 2 self, 3 connection=None, 4 url=None, 5 dialect_name=None, 6 dialect_opts=None, 7 transactional_ddl=None, 8 transaction_per_migration=False, 9 output_buffer=None, 10 starting_rev=None, 11 tag=None, 12 template_args=None, 13 render_as_batch=False, 14 target_metadata=None, 15 include_name=None, 16 include_object=None, 17 include_schemas=False, 18 process_revision_directives=None, 19 compare_type=False, 20 compare_server_default=False, 21 render_item=None, 22 literal_binds=False, 23 upgrade_token="upgrades", 24 downgrade_token="downgrades", 25 alembic_module_prefix="op.", 26 sqlalchemy_module_prefix="sa.", 27 user_module_prefix=None, 28 on_version_apply=None, 29 **kw 30 ):
這里有一個熟悉的面孔,沒錯!二號坑里的render_as_batch參數也在這里。同時,還有一個叫做compare_type的參數,默認是False,該參數用於標注是否比較字段屬性變化。所以,同二號坑,在初始化Migrate對象的時候加入該參數,如下:
Migrate(db=db, render_as_batch=True, compare_type=True)
第四坑:default默認約束的生成
sqlalchemy的默認值設置有兩種方式,第一種是直接的在Column中設置default,這種方式並不在數據庫生成默認值約束,是依靠sqlalchemy自身的功能在生成數據的時候生成默認值。另一種是server_default,這種方式是直接在數據庫內生成默認值約束。使用較為麻煩,因為server_default參數只接受str或者unicode這種類型,比如Integer字段也需要設置為字符串,時間戳則需要自己轉化,較為麻煩。所以,想要在數據遷移時生成數據庫的約束,需要使用server_default而不是default。此外,在三號坑內的源碼里,也能看見一個熟臉,就是compare_server_default,默認值是False。
解決方法:
1.保證model內所有有默認值的字段的default以server_default形式設置。
2.初始化Migrate對象時做配置:migrate = Migrate(db=db, render_as_batch=True, compare_type=True, compare_server_default=True)
除了以上4個比較常見的坑外,其實還有很多,不過我在學習過程中遇到暫時就只有這四個,后續如果遇到會補充。
參考博客:https://blog.csdn.net/c_s_y/article/details/90769675