了解flask_migrate需要先了解flask-script露该,那么flask-script的作用是什么呢脱衙?flask-script的作用是可以通過(guò)命令行的形式來(lái)操作Flask嘀趟。例如通過(guò)命令跑一個(gè)開(kāi)發(fā)版本的服務(wù)器、設(shè)置數(shù)據(jù)庫(kù)甥捺,定時(shí)任務(wù)等邮绿。
2.執(zhí)行pip install flask-script
來(lái)進(jìn)行安裝渠旁。
- 如果直接在主
manage.py
中寫(xiě)命令,那么在終端就只需要python manage.py command_name
就可以了船逮。 - 如果把一些命令集中在一個(gè)文件中顾腊,那么在終端就需要輸入一個(gè)父命令,比如
python manage.py db init
挖胃。
app.py文件
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
manager.py文件
# encoding: utf-8
from flask_script import Manager
from app import app
manager = Manager(app)
@manager.command
def run():
print("服務(wù)器跑起來(lái)了")
if __name__ == '__main__':
manager.run()
在終端運(yùn)行杂靶,run代表的是manager.py中的方法
python manage.py run
服務(wù)器跑起來(lái)了
flask-script我們一般和數(shù)據(jù)庫(kù)在一起使用
app.py文件
#encoding: utf-8
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
manage.py文件
#encoding: utf-8
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
db_scripts.py文件
# encoding: utf-8
from flask_script import Manager
DBManager = Manager()
@DBManager.command
def init():
print('數(shù)據(jù)庫(kù)初始化完成')
@DBManager.command
def migrate():
print('數(shù)據(jù)表遷移成功')
首先執(zhí)行如下命令:
python manage.py db init
數(shù)據(jù)庫(kù)初始化完成
再執(zhí)行命令
python manage.py db migrate
數(shù)據(jù)表遷移成功
上面使用flask-script的使用以及對(duì)數(shù)據(jù)庫(kù)的演示承耿,實(shí)際開(kāi)發(fā)中我們使用flask-migrate來(lái)動(dòng)態(tài)的遷移數(shù)據(jù)庫(kù),使用flask-migrate必須借助flask-script伪煤。
Flask-Migrate的介紹與安裝:
pip install flask-migrate
搞起!A堇薄抱既!
migrate_demo.py文件
from flask import Flask
import config
from exts import db
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
exts.py文件
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
config.py文件
DIALECT = 'mysql'
DRIVER = 'pymysql'
USERNAME = 'root'
PASSWORD = '123456'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'pythonflask'
SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT, DRIVER, USERNAME, PASSWORD, HOST, PORT,
DATABASE)
SQLALCHEMY_TRACK_MODIFICATIONS = False
models.py
from exts import db
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
manage.py,這個(gè)是最重要的文件:
from flask_script import Manager
from migrate_demo import app
from flask_migrate import Migrate,MigrateCommand
from exts import db
from models import Article
manager = Manager(app)
# 1. 要使用flask_migrate扁誓,必須綁定app和db
migrate = Migrate(app,db)
# 2. 把MigrateCommand命令添加到manager中
manager.add_command('db',MigrateCommand)
if __name__ == '__main__':
manager.run()
我們使用的是pythonflask這個(gè)數(shù)據(jù)庫(kù)防泵,里面沒(méi)有任何的表和數(shù)據(jù)。
- 終端執(zhí)行命令第一個(gè)命令:
python manage.py db init
上面的命令執(zhí)行后蝗敢,在我們的項(xiàng)目中會(huì)生成一個(gè)migrations文件夾捷泞,如下所示,versions中沒(méi)有任何內(nèi)容:
上面的命令執(zhí)行完后寿谴,來(lái)看看數(shù)據(jù)庫(kù)發(fā)生變化沒(méi)有:
可以看出锁右,此時(shí)數(shù)據(jù)庫(kù)沒(méi)有發(fā)生任何變化。
- 上面的命令成功后讶泰,執(zhí)行如下命令咏瑟,將模型生成遷移文件:
python manage.py db init
如下所示,versions文件夾中生成了一個(gè)文件c6439ddd759f_.py痪署,這個(gè)就是遷移文件码泞。
c6439ddd759f_.py:
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'c6439ddd759f'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('article',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('title', sa.String(length=100), nullable=False),
sa.Column('content', sa.Text(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('article')
# ### end Alembic commands ###
再來(lái)看看數(shù)據(jù)庫(kù)發(fā)生了什么變化:
這時(shí)多了一個(gè)alembic_version文件,這個(gè)文件是遷移文件的版本號(hào)狼犯。
- 接下來(lái)執(zhí)行最后一個(gè)命令余寥,將遷移文件真正的映射到數(shù)據(jù)庫(kù)中:
python manage.py db upgrade
查看數(shù)據(jù)庫(kù)的變化:
可以看出,這個(gè)命令執(zhí)行完后悯森,數(shù)據(jù)才真正的遷移到數(shù)據(jù)庫(kù)了宋舷。
現(xiàn)在article中我們可以看到只有如下字段:
那這時(shí)候如果我想再插入一個(gè)字段,該如何操作呢呐馆?只需要把上面的命令執(zhí)行一遍就可以肥缔,但不是每個(gè)命令都執(zhí)行的。
python manage.py db init
:這個(gè)命令不需要執(zhí)行汹来,因?yàn)橐呀?jīng)初始化了遷移腳本的環(huán)境续膳,這個(gè)命令只執(zhí)行一次。
python manage.py db migrate
:這個(gè)命令需要執(zhí)行收班,因?yàn)槟P透淖兞恕?/p>
python manage.py db upgrade
這個(gè)命令也需要執(zhí)行坟岔,每次運(yùn)行了migrate
命令后,就記得要運(yùn)行這個(gè)命令摔桦。
增加的這個(gè)字段為“name”:
class Article(db.Model):
__tablename__ = 'article'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(100), nullable=False)
name = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
命令執(zhí)行完后社付,查看數(shù)據(jù)庫(kù):
更新成功了3衅!!E缚АQ喔搿!L淅薄啊研!
總結(jié)如下:
- 介紹:因?yàn)椴捎?code>db.create_all在后期修改字段的時(shí)候,不會(huì)自動(dòng)的映射到數(shù)據(jù)庫(kù)中鸥拧,必須刪除表党远,然后重新運(yùn)行
db.craete_all
才會(huì)重新映射,這樣不符合我們的需求富弦。因此flask-migrate就是為了解決這個(gè)問(wèn)題沟娱,它可以在每次修改模型后,可以將修改的東西映射到數(shù)據(jù)庫(kù)中腕柜。 - 使用
flask_migrate
必須借助flask_scripts
济似,這個(gè)包的MigrateCommand
中包含了所有和數(shù)據(jù)庫(kù)相關(guān)的命令。 -
flask_migrate
相關(guān)的命令:-
python manage.py db init
:初始化一個(gè)遷移腳本的環(huán)境盏缤,只需要執(zhí)行一次碱屁。 -
python manage.py db migrate
:將模型生成遷移文件,只要模型更改了蛾找,就需要執(zhí)行一遍這個(gè)命令娩脾。 -
python manage.py db upgrade
:將遷移文件真正的映射到數(shù)據(jù)庫(kù)中。每次運(yùn)行了migrate
命令后打毛,就記得要運(yùn)行這個(gè)命令柿赊。
-
- 注意點(diǎn):需要將你想要映射到數(shù)據(jù)庫(kù)中的模型,都要導(dǎo)入到
manage.py
文件中幻枉,如果沒(méi)有導(dǎo)入進(jìn)去碰声,就不會(huì)映射到數(shù)據(jù)庫(kù)中。
最后我們可以隨心所欲的來(lái)對(duì)數(shù)據(jù)庫(kù)進(jìn)行增刪改查了熬甫,簡(jiǎn)單的在article中插入一條數(shù)據(jù)胰挑,修改migrate_demo.py文件:
from flask import Flask
import config
from exts import db
from models import Article
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
# 新增數(shù)據(jù)
@app.route('/addData')
def addData():
article = Article(title='aaaa', content='dsfsdf')
db.session.add(article)
db.session.commit()
return 'Hello World!'
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)