認(rèn)識(shí)Flask-SQLAlchemy
- Flask-SQLAlchemy 是一個(gè)為 Flask 應(yīng)用增加 SQLAlchemy 支持的擴(kuò)展。它致力于簡(jiǎn)化在 Flask 中 SQLAlchemy 的使用。
- SQLAlchemy 是目前python中最強(qiáng)大的 ORM框架, 功能全面, 使用簡(jiǎn)單。
ORM優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 有語(yǔ)法提示, 省去自己拼寫SQL,保證SQL語(yǔ)法的正確性
- orm提供方言功能(dialect, 可以轉(zhuǎn)換為多種數(shù)據(jù)庫(kù)的語(yǔ)法), 減少學(xué)習(xí)成本
- 防止sql注入攻擊
- 搭配數(shù)據(jù)遷移, 更新數(shù)據(jù)庫(kù)方便
- 面向?qū)ο? 可讀性強(qiáng), 開發(fā)效率高
缺點(diǎn)
- 需要語(yǔ)法轉(zhuǎn)換, 效率比原生sql低
- 復(fù)雜的查詢往往語(yǔ)法比較復(fù)雜 (可以使用原生sql替換)
環(huán)境安裝
pip install flask-sqlalchemy
flask-sqlalchemy 在安裝/使用過程中, 如果出現(xiàn) ModuleNotFoundError: No module named 'MySQLdb’錯(cuò)誤, 則表示缺少mysql依賴包, 可依次嘗試下列兩個(gè)方案后重試:
方案1: 安裝 mysqlclient依賴包 (如果失敗再嘗試方案2)pip install mysqlclient
方案2: 安裝pymysql依賴包pip install pymysql
mysqlclient 和 pymysql 都是用于mysql訪問的依賴包, 前者由C語(yǔ)言實(shí)現(xiàn)的, 而后者由python實(shí)現(xiàn), 前者的執(zhí)行效率比后者更高, 但前者在windows系統(tǒng)中兼容性較差, 工作中建議優(yōu)先前者。
組件初始化
基本配置
flask-sqlalchemy 的相關(guān)配置也封裝到了 flask 的配置項(xiàng)中, 可以通過app.config屬性 或 配置加載方案 (如config.from_object) 進(jìn)行設(shè)置
數(shù)據(jù)庫(kù)URI(連接地址)格式: 協(xié)議名://用戶名:密碼@數(shù)據(jù)庫(kù)IP:端口號(hào)/數(shù)據(jù)庫(kù)名, 如:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
注意點(diǎn)如果數(shù)據(jù)庫(kù)驅(qū)動(dòng)使用的是 pymysql, 則協(xié)議名需要修改為
mysql+pymysql://xxxxxxx
?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 設(shè)置數(shù)據(jù)庫(kù)連接地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
# 是否追蹤數(shù)據(jù)庫(kù)修改(開啟后會(huì)觸發(fā)一些鉤子函數(shù)) ?一般不開啟, 會(huì)影響性能
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 是否顯示底層執(zhí)行的SQL語(yǔ)句
app.config['SQLALCHEMY_ECHO'] = True
兩種初始化方式
.方式1
flask-sqlalchemy 支持兩種組件初始化方式:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 應(yīng)用配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
# 方式1: 初始化組件對(duì)象, 直接關(guān)聯(lián)Flask應(yīng)用
db = SQLAlchemy(app)
方式2: 先創(chuàng)建組件, 延后關(guān)聯(lián)Flass應(yīng)用
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# 方式2: 初始化組件對(duì)象, 延后關(guān)聯(lián)Flask應(yīng)用
db = SQLAlchemy()
def create_app(config_type):
? ? """工廠函數(shù)"""
? ? # 創(chuàng)建應(yīng)用
? ? flask_app = Flask(__name__)
? ? # 加載配置
? ? config_class = config_dict[config_type]
? ? flask_app.config.from_object(config_class)
? ? # 關(guān)聯(lián)flask應(yīng)用
? ? db.init_app(app)
? ? return flask_app
構(gòu)建模型類
flask-sqlalchemy 的關(guān)系映射和 Django-orm 類似
類 對(duì)應(yīng) 表
類屬性 對(duì)應(yīng) 字段
實(shí)例對(duì)象 對(duì)應(yīng) 記錄
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
import pymysql as MySQLdb
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:yu201541010@127.0.0.1:3306/pythontest'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
# 創(chuàng)建組件對(duì)象
db = SQLAlchemy(app)
# 構(gòu)建模型類 類->表 類屬性->字段 實(shí)例對(duì)象->記錄
class User(db.Model):
__tablename__ = 't_user' # 設(shè)置表名, 表名默認(rèn)為類名小寫
id = db.Column(db.Integer, primary_key=True) # 設(shè)置主鍵, 默認(rèn)自增
name = db.Column('username', db.String(20), unique=True) # 設(shè)置字段名 和 唯一約束
age = db.Column(db.Integer, default=10, index=True) # 設(shè)置默認(rèn)值約束 和 索引
with app.app_context():
db.create_all()
if __name__ == '__main__':
app.run(debug=True)
注意點(diǎn)
- 模型類必須繼承 db.Model, 其中 db 指對(duì)應(yīng)的組件對(duì)象
- 表名默認(rèn)為類名小寫, 可以通過 __tablename__類屬性 進(jìn)行修改
- 類屬性對(duì)應(yīng)字段, 必須是通過 db.Column() 創(chuàng)建的對(duì)象
- 可以通過 create_all() 和 drop_all()方法 來創(chuàng)建和刪除所有模型類對(duì)應(yīng)的表常用的字段類型
常用的字段選項(xiàng)
注意點(diǎn): 如果沒有給對(duì)應(yīng)字段的類屬性設(shè)置default參數(shù), 且添加數(shù)據(jù)時(shí)也沒有給該字段賦值, 則sqlalchemy會(huì)給該字段設(shè)置默認(rèn)值 None
?
數(shù)據(jù)操作
增加數(shù)據(jù)
@app.route('/')
def index():
# 增加數(shù)據(jù)
user1 = User(name = 'zs', age = 20)
#將模型對(duì)象添加到會(huì)話中
db.session.add(user1)
db.session.commit()
return "index"
注意點(diǎn):
這里的 會(huì)話 并不是 狀態(tài)保持機(jī)制中的 session,而是 sqlalchemy 的會(huì)話。它被設(shè)計(jì)為 數(shù)據(jù)操作的執(zhí)行者, 從SQL角度則可以理解為是一個(gè) 加強(qiáng)版的數(shù)據(jù)庫(kù)事務(wù)
sqlalchemy 會(huì) 自動(dòng)創(chuàng)建事務(wù), 并將數(shù)據(jù)操作包含在事務(wù)中, 提交會(huì)話時(shí)就會(huì)提交事務(wù)
事務(wù)提交失敗會(huì)自動(dòng)回滾
查詢數(shù)據(jù)
class Users(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
email = db.Column(db.String(64))
age = db.Column(db.Integer)
def __repr__(self):
return "(%s, %s, %s, %s)" % (self.id, self.name, self.email, self.age)
@app.route('/createusers')
def createusers():
user1 = Users(name='wang', email='wang@163.com', age=20)
user2 = Users(name='zhang', email='zhang@189.com', age=33)
user3 = Users(name='chen', email='chen@126.com', age=23)
user4 = Users(name='zhou', email='zhou@163.com', age=29)
user5 = Users(name='tang', email='tang@itheima.com', age=25)
user6 = Users(name='wu', email='wu@gmail.com', age=25)
user7 = Users(name='qian', email='qian@gmail.com', age=23)
user8 = Users(name='liu', email='liu@itheima.com', age=30)
user9 = Users(name='li', email='li@163.com', age=28)
user10 = Users(name='sun', email='sun@163.com', age=26)
db.session.add_all([user1, user2, user3, user5, user4, user6, user7, user8,user9,user10])
db.session.commit()
return "success"
@app.route('/query')
def query():
user = Users.query.first()
return user.name+" "+user.email
# 查詢所有用戶數(shù)據(jù)
User.query.all() 返回列表, 元素為模型對(duì)象# 查詢有多少個(gè)用戶
User.query.count()# 查詢第1個(gè)用戶
User.query.first() ?返回模型對(duì)象/None# 查詢id為4的用戶[3種方式]
# 方式1: 根據(jù)id查詢 ?返回模型對(duì)象/None
User.query.get(4) ?# 方式2: 等值過濾器 關(guān)鍵字實(shí)參設(shè)置字段值 ?返回BaseQuery對(duì)象
# BaseQuery對(duì)象可以續(xù)接其他過濾器/執(zhí)行器 ?如 all/count/first等
User.query.filter_by(id=4).all() ?# 方式3: 復(fù)雜過濾器 ?參數(shù)為比較運(yùn)算/函數(shù)引用等 ?返回BaseQuery對(duì)象
User.query.filter(User.id == 4).first() ?# 查詢名字結(jié)尾字符為g的所有用戶[開始 / 包含]
User.query.filter(User.name.endswith("g")).all()
User.query.filter(User.name.startswith("w")).all()
User.query.filter(User.name.contains("n")).all()
User.query.filter(User.name.like("w%n%g")).all() ?# 模糊查詢# 查詢名字和郵箱都以li開頭的所有用戶[2種方式]
User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
from sqlalchemy import and_
User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all()# 查詢age是25 或者 `email`以`itheima.com`結(jié)尾的所有用戶
from sqlalchemy import or_
User.query.filter(or_(User.age==25, User.email.endswith("itheima.com"))).all()# 查詢名字不等于wang的所有用戶[2種方式]
from sqlalchemy import not_
User.query.filter(not_(User.name == 'wang')).all()
User.query.filter(User.name != 'wang').all()# 查詢id為[1, 3, 5, 7, 9]的用戶
User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()# 所有用戶先按年齡從小到大, 再按id從大到小排序, 取前5個(gè)
User.query.order_by(User.age, User.id.desc()).limit(5).all()# 查詢年齡從小到大第2-5位的數(shù)據(jù) ? 2 3 4 5
User.query.order_by(User.age).offset(1).limit(4).all()# 分頁(yè)查詢, 每頁(yè)3個(gè), 查詢第2頁(yè)的數(shù)據(jù) ?paginate(頁(yè)碼, 每頁(yè)條數(shù))
pn = User.query.paginate(2, 3)
pn.pages 總頁(yè)數(shù) ?pn.page 當(dāng)前頁(yè)碼 pn.items 當(dāng)前頁(yè)的數(shù)據(jù) ?pn.total 總條數(shù)# 查詢每個(gè)年齡的人數(shù) ? ?select age, count(name) from t_user group by age ?分組聚合
from sqlalchemy import func
data = db.session.query(User.age, func.count(User.id).label("count")).group_by(User.age).all()
for item in data:
? ? # print(item[0], item[1])
? ? print(item.age, item.count) ?# 建議通過label()方法給字段起別名, 以屬性方式獲取數(shù)據(jù)
# 只查詢所有人的姓名和郵箱 ?優(yōu)化查詢 ? User.query.all() ?# 相當(dāng)于select *
from sqlalchemy.orm import load_only
data = User.query.options(load_only(User.name, User.email)).all() ?# flask-sqlalchem的語(yǔ)法
for item in data:
? ? print(item.name, item.email)data = db.session.query(User.name, User.email).all() ?# sqlalchemy本體的語(yǔ)法
for item in data:
? ? print(item.name, item.email)
更新數(shù)據(jù)
flask-sqlalchemy 提供了兩種更新數(shù)據(jù)的方案?
先查詢, 再更新
對(duì)應(yīng)SQL中的 先select, 再update
基于過濾條件的更新 (推薦方案)
對(duì)應(yīng)SQL中的 update xx where xx = xx (也稱為 update子查詢 )
先查詢, 再更新
這種方式的缺點(diǎn)
查詢和更新分兩條語(yǔ)句, 效率低
如果并發(fā)更新, 可能出現(xiàn)更新丟失問題(Lost Update)
class Goods(db.Model):
__tablename__ = 't_good'
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(20), unique=True)
count = db.Column(db.Integer)
@app.route('/addgood')
def addgood():
goods = Goods(name='方便面', count=10)
db.session.add(goods)
db.session.commit()
return "success"
@app.route('/updategood')
def updategood():
goods = Goods.query.filter(Goods.name=='方便面').first()
goods.count = goods.count - 1
db.session.commit()
return "success"
基于過濾條件的更新
這種方式的優(yōu)點(diǎn):
一條語(yǔ)句, 被網(wǎng)絡(luò)IO影響程度低, 執(zhí)行效率更高
查詢和更新在一條語(yǔ)句中完成, 單條SQL具有原子性, 不會(huì)出現(xiàn)更新丟失問題
會(huì)對(duì)滿足過濾條件的所有記錄進(jìn)行更新, 可以實(shí)現(xiàn)批量更新處理
操作步驟如下:
配合 查詢過濾器filter() 和 更新執(zhí)行器update() 進(jìn)行數(shù)據(jù)更新
提交會(huì)話
@app.route('/updategood2')
def updategood2():
Goods.query.filter(Goods.name=='方便面').update({'count':Goods.count-1})
db.session.commit()
return "success"
刪除數(shù)據(jù)
類似更新數(shù)據(jù), 也存在兩種刪除數(shù)據(jù)的方案
先查詢, 再刪除
對(duì)應(yīng)SQL中的 先select, 再delete
基于過濾條件的刪除 (推薦方案)
對(duì)應(yīng)SQL中的 delete xx where xx = xx (也稱為 delete子查詢 )
這種方式的缺點(diǎn):
查詢和刪除分兩條語(yǔ)句, 效率低
@app.route('/deletegood')
def deletegood():
goods = Goods.query.filter(Goods.name=='方便面').first()
db.session.delete(goods)
db.session.commit()
return "success"
基于過濾條件的刪除
這種方式的優(yōu)點(diǎn):
一條語(yǔ)句, 被網(wǎng)絡(luò)IO影響程度低, 執(zhí)行效率更高
會(huì)對(duì)滿足過濾條件的所有記錄進(jìn)行刪除, 可以實(shí)現(xiàn)批量刪除處理
操作步驟如下:
配合 查詢過濾器filter() 和 刪除執(zhí)行器delete() 進(jìn)行數(shù)據(jù)刪除
提交會(huì)話
@app.route('/deletegood2')
def deletegood2():
Goods.query.filter(Goods.name=='方便面').delete()
db.session.commit()
return "success"
增刪改操作都需要提交會(huì)話, 對(duì)應(yīng)事務(wù)中進(jìn)行數(shù)據(jù)庫(kù)變化后提交事務(wù)
刷新數(shù)據(jù)
Session 被設(shè)計(jì)為數(shù)據(jù)操作的執(zhí)行者, 會(huì)先將操作產(chǎn)生的數(shù)據(jù)保存到內(nèi)存中
在執(zhí)行 flush刷新操作 后, 數(shù)據(jù)操作才會(huì)同步到數(shù)據(jù)庫(kù)中
有兩種情況下會(huì) 隱式執(zhí)行刷新操作
提交會(huì)話
執(zhí)行查詢操作 (包括 update 和 delete 子查詢)
開發(fā)者也可以 手動(dòng)執(zhí)行刷新操作 session.flush()
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test31'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# 構(gòu)建模型類 ?
class Goods(db.Model):
? ? __tablename__ = 't_good' ?
? ? id = db.Column(db.Integer, primary_key=True)?
? ? name = db.Column(db.String(20), unique=True)?
? ? count = db.Column(db.Integer) ?
@app.route('/')
def purchase():
? ? goods = Goods(name='方便面', count=20)
? ? db.session.add(goods)
? ? # 主動(dòng)執(zhí)行flush操作, 立即執(zhí)行SQL操作(數(shù)據(jù)庫(kù)同步)
? ? db.session.flush()
? ? # Goods.query.count() ?# 查詢操作會(huì)自動(dòng)執(zhí)行flush操作
? ? db.session.commit() ?# 提交會(huì)話會(huì)自動(dòng)執(zhí)行flush操作
? ? return "index"
if __name__ == '__main__':
? ? db.drop_all()
? ? db.create_all()
? ? app.run(debug=True)
多表查詢
案例中包含兩個(gè)模型類: User用戶模型 和 Address地址模型, 并且一個(gè)用戶可以有多個(gè)地址, 兩張表之間存在一對(duì)多關(guān)系
class Address(db.Model):
__tablename__='t_adr'
id = db.Column(db.Integer, primary_key=True)
detail = db.Column(db.String(20))
user_id = db.Column(db.Integer)
@app.route('/addadr')
def addadr():
adr1 = Address(detail='中關(guān)村3號(hào)', user_id=1)
adr2 = Address(detail='華強(qiáng)北5號(hào)', user_id=1)
db.session.add_all([adr2, adr1])
db.session.commit()
return "success"
關(guān)聯(lián)查詢
關(guān)聯(lián)查詢步驟: (以主查從為例)
先查詢主表數(shù)據(jù)
再通過外鍵字段查詢 關(guān)聯(lián)的從表數(shù)據(jù)
@app.route('/queryadr')
def queryadr():
user1 = User.query.filter_by(name='zs').first()
adrs = Address.query.filter_by(user_id=user1.id).all()
for adr in adrs:
print(adr.detail)
return "success"
連接查詢
開發(fā)中有 聯(lián)表查詢需求 時(shí), 一般會(huì)使用 join連接查詢
sqlalchemy 也提供了對(duì)應(yīng)的查詢語(yǔ)法
db.session.query(主表模型字段1, 主表模型字段2, 從表模型字段1, xx.. ).join(從表模型類, 主表模型類.主鍵 == 從表模型類.外鍵)
1
join語(yǔ)句 屬于查詢過濾器, 返回值也是 BaseQuery 類型對(duì)象
@app.route('/queryadr2')
def queryadr2():
data = db.session.query(User.id, Address.detail).join(Address, User.id==Address.user_id).filter(User.name=='zs').all()
for item in data:
print(item.detail, item.id)
return "success"
關(guān)聯(lián)查詢的性能優(yōu)化
通過前邊的學(xué)習(xí), 可以發(fā)現(xiàn) 無論使用 外鍵 還是 關(guān)系屬性 查詢關(guān)聯(lián)數(shù)據(jù), 都需要查詢兩次, 一次查詢用戶數(shù)據(jù), 一次查詢地址數(shù)據(jù)
兩次查詢就需要發(fā)送兩次請(qǐng)求給數(shù)據(jù)庫(kù)服務(wù)器, 如果數(shù)據(jù)庫(kù)和web應(yīng)用不在一臺(tái)服務(wù)器中, 則 網(wǎng)絡(luò)IO會(huì)對(duì)查詢效率產(chǎn)生一定影響
可以考慮使用 連接查詢 join 使用一條語(yǔ)句就完成關(guān)聯(lián)數(shù)據(jù)的查詢
# 使用join語(yǔ)句優(yōu)化關(guān)聯(lián)查詢
adrs = Address.query.join(User, Address.user_id == User.id).filter(User.name == '張三').all() ?# 列表中包含地址模型對(duì)象
Session機(jī)制
生命周期
flask-sqlalchemy 對(duì)于 sqlalchemy本體 的 Session 進(jìn)行了一定的封裝:
Session的生命周期和請(qǐng)求相近?
請(qǐng)求中的首次數(shù)據(jù)操作會(huì)創(chuàng)建Session
整個(gè)請(qǐng)求過程中使用的Session為同一個(gè), 并且線程隔離
請(qǐng)求結(jié)束時(shí)會(huì)自動(dòng)銷毀Session(釋放內(nèi)存)
Session和事務(wù)
Session中可以包含多個(gè)事務(wù), 提交事務(wù)失敗后, 會(huì)自動(dòng)執(zhí)行SQL的回滾操作
同一個(gè)請(qǐng)求中, 想要在前一個(gè)事務(wù)失敗的情況下創(chuàng)建新的事務(wù), 必須先手動(dòng)回滾事務(wù) Session.rollback
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/toutiao'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# 構(gòu)建模型類?
class User(db.Model):
? ? __tablename__ = 't_user' ?
? ? id = db.Column(db.Integer, primary_key=True) ?
? ? name = db.Column('username', db.String(20), unique=True)?
? ? age = db.Column(db.Integer, default=0, index=True) ?
@app.route('/')
def index():
? ? """事務(wù)1"""
? ? try:
? ? ? ? user1 = User(name='zs', age=20)
? ? ? ? db.session.add(user1)
? ? ? ? db.session.commit()
? ? except BaseException:
? ? ? ? # 手動(dòng)回滾 ? 同一個(gè)session中, 前一個(gè)事務(wù)如果失敗, 必須手動(dòng)回滾, 否則無法創(chuàng)建新的事務(wù)
? ? ? ? db.session.rollback()
? ? """事務(wù)2"""
? ? user1 = User(name='lisi', age=30)
? ? db.session.add(user1)
? ? db.session.commit()
? ? return "index"
if __name__ == '__main__':
? ? """為了進(jìn)行測(cè)試, 首次運(yùn)行 建表并添加一條測(cè)試數(shù)據(jù)后, 注釋下方代碼, 并重新運(yùn)行測(cè)試"""
? ? # 重置所有繼承自db.Model的表
? ? # db.drop_all()
? ? # db.create_all()
? ? # 添加一條測(cè)試數(shù)據(jù)
? ? # user1 = User(name='zs', age=20)
? ? # db.session.add(user1)
? ? # db.session.commit()
? ? app.run(debug=True)
數(shù)據(jù)遷移
flask-migrate組件 為flask-sqlalchemy提供了數(shù)據(jù)遷移功能, 以便進(jìn)行數(shù)據(jù)庫(kù)升級(jí), 如增加字段、修改字段類型等
安裝組件 pip install flask-migrate
# hm_數(shù)據(jù)遷移.py?
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:yu201541010@127.0.0.1:3306/pythontest'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
#遷移組件初始化
Migrate(app, db)
class User(db.Model):
__tablename__ ='t_user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column('username', db.String(20), unique=True)
@app.route('/')
def index():
return "index"
if __name__ =='__main__':
app.run()
執(zhí)行遷移命令
終端進(jìn)入當(dāng)前文件目錄下,注意export命令后面等號(hào)不能有空格文章來源:http://www.zghlxwxcb.cn/news/detail-650705.html
- export FLASK_APP=hm_數(shù)據(jù)遷移.py ?# 設(shè)置環(huán)境變量指定啟動(dòng)文件
- flask db init ?# 生成遷移文件夾 ?只執(zhí)行一次
- flask db migrate ?# ?成遷移版本, 保存到遷移文件夾中
- flask db upgrade ?# 執(zhí)行遷移
執(zhí)行遷移命令前需要先設(shè)置環(huán)境變量指定啟動(dòng)文件文章來源地址http://www.zghlxwxcb.cn/news/detail-650705.html
到了這里,關(guān)于Flask-SQLAlchemy的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!