Flask-Migrate的使用和常見"坑"的解決辦法


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     ):
View Code

這里有一個熟悉的面孔,沒錯!二號坑里的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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM