Flask-Sqlalchemy的基本使用詳解
一: 基本使用:
1:環(huán)境的安裝:
pip install flask-sqlalchemy pip install pymysql
2:組件初始化:
2.1: 基本的配置
1: 首先先安裝兩個(gè)依賴的包。
2:配置數(shù)據(jù)庫(kù)的連接:app.config[‘SQLALCHEMY_DATABASE_URI’] = “mysql://root:mysql@192.168.44.128:3306/test39”
3:關(guān)閉數(shù)據(jù)庫(kù)的跟蹤:app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False
4:開(kāi)啟輸出sql語(yǔ)句:app.config[‘SQLALCHEMY_ECHO’] = True
5:兩種處理python2和python3的名字不一致問(wèn)題。
from flask import Flask
from flask_restful import Api, Resource
from flask_sqlalchemy import SQLAlchemy
import pymysql
pymysql.install_as_MySQLdb()
"""
python2中數(shù)據(jù)庫(kù)客戶端: MySqldb
python3中數(shù)據(jù)庫(kù)客戶端:pymysql
解決方案一:讓python2和python3的包進(jìn)行轉(zhuǎn)換。
import pymysql
pymysql.install_as_MySQLdb()
方案二:表示只使用python3的包,不使用python2的包
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:mysql@192.168.44.128:3306/test39"
"""
app = Flask(__name__)
db = SQLAlchemy(app)
# app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://賬號(hào):密碼@數(shù)據(jù)庫(kù)ip地址:端口號(hào)/數(shù)據(jù)庫(kù)名"
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:mysql@192.168.44.128:3306/test39"
# app.config['SQLALCHEMY_BINDS'] = {}
# 關(guān)閉數(shù)據(jù)庫(kù)修改跟蹤操作[提高性能]:
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 開(kāi)啟輸出底層執(zhí)行的sql語(yǔ)句
app.config['SQLALCHEMY_ECHO'] = True
# 開(kāi)啟數(shù)據(jù)庫(kù)的自動(dòng)提交功能[一般不使用]
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
@app.route('/')
def hello_word():
return "hello, word"
if __name__ == '__main__':
print(app.url_map)
app.run(host='0.0.0.0', port= 8000, debug=True)
2.2:結(jié)合工廠方法進(jìn)行配置:
1: 數(shù)據(jù)庫(kù)配置信息存放在環(huán)境類中加載。
2:由于數(shù)據(jù)庫(kù)對(duì)象和app對(duì)象不一定誰(shuí)先創(chuàng)建,所以可以先創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象,等app對(duì)象創(chuàng)建之后再進(jìn)行關(guān)聯(lián)。
3:進(jìn)行關(guān)聯(lián)的函數(shù)是:數(shù)據(jù)庫(kù)對(duì)象調(diào)用自己的init_app()方法。需要傳入app對(duì)象。
settings中配置:
# 開(kāi)發(fā)環(huán)境
class DevelopmentConfig(BaseConfig):
"""開(kāi)發(fā)環(huán)境配置類"""
DEBUG = True
# SQL數(shù)據(jù)庫(kù)連接信息
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:mysql@192.168.243.157:3306/test39"
# 關(guān)閉數(shù)據(jù)庫(kù)修改跟蹤操作 【提高性能】
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 開(kāi)啟輸出底層執(zhí)行sql語(yǔ)句
SQLALCHEMY_ECHO = True
主模塊:
from flask import Flask, make_response, Response, request, current_app
from settings import config_dict
from flask_sqlalchemy import SQLAlchemy
# 延后加載
# 創(chuàng)建了數(shù)據(jù)庫(kù),此時(shí)數(shù)據(jù)庫(kù)對(duì)象還沒(méi)有跟app關(guān)聯(lián)
db = SQLAlchemy()
# 定義一個(gè)工廠方法:
def create_app(config_name):
app = Flask(__name__)
config_class = config_dict[config_name]
app.config.from_object(config_class)
app.config.from_envvar('CONFIG', silent=True)
# 懶加載
db.init_app(app)
return app
app = create_app("dev")
@app.route('/login')
def login():
return ""
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
3:構(gòu)建模型類:
- 模型類必須繼承 db.Model, 其中 db 指對(duì)應(yīng)的組件對(duì)象
- 表名默認(rèn)為類名小寫, 可以通過(guò) __tablename__類屬性 進(jìn)行修改
- 類屬性對(duì)應(yīng)字段, 必須是通過(guò) db.Column() 創(chuàng)建的對(duì)象
- 可以通過(guò) create_all() 和 drop_all()方法 來(lái)創(chuàng)建和刪除所有模型類對(duì)應(yīng)的表
- 注意點(diǎn): 如果沒(méi)有給對(duì)應(yīng)字段的類屬性設(shè)置default參數(shù), 且添加數(shù)據(jù)時(shí)也沒(méi)有給該字段賦值, 則 sqlalchemy會(huì)給該字段設(shè)置默認(rèn)值 None
<模型類創(chuàng)建案例>
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:mysql@192.168.44.128:3306/test39"
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)值約束 和 索引
if __name__ == '__main__':
# 刪除所有繼承自db.Model的表
db.drop_all()
# 創(chuàng)建所有繼承自db.Model的表
db.create_all()
app.run(host="0.0.0.0", port=8000, debug=True)
二:數(shù)據(jù)操作:
1:增加數(shù)據(jù):
1:給模型對(duì)象設(shè)置數(shù)據(jù) 可以通過(guò) 初始化參數(shù) 或者 賦值屬性 兩種方式
2:session.add(模型對(duì)象) 添加單條數(shù)據(jù)到會(huì)話中, session.add_all(列表) 添加多條數(shù)據(jù)到會(huì)話中
3:sqlalchemy 會(huì) 自動(dòng)創(chuàng)建事務(wù), 并將數(shù)據(jù)操作包含在事務(wù)中, 提交會(huì)話時(shí)就會(huì)提交事務(wù),事務(wù)提交失敗會(huì)自動(dòng)回滾。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:mysql@192.168.44.128:3306/test39"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
# 創(chuàng)建組件對(duì)象
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, index=True)
@app.route('/')
def index():
"""增加數(shù)據(jù)"""
# 1.創(chuàng)建模型對(duì)象
user1 = User(name='zs', age=20)
# user1.name = 'zs'
# user1.age = 20
# 2.將模型對(duì)象添加到會(huì)話中
db.session.add(user1)
# 添加多條記錄
# db.session.add_all([user1, user2, user3])
# 3.提交會(huì)話 (會(huì)提交事務(wù))
# sqlalchemy會(huì)自動(dòng)創(chuàng)建隱式事務(wù)
# 事務(wù)失敗會(huì)自動(dòng)回滾
db.session.commit()
return "index"
if __name__ == '__main__':
db.drop_all()
db.create_all()
app.run(host="0.0.0.0", port=8000, debug=True)
2:查詢數(shù)據(jù):


1:數(shù)據(jù)的準(zhǔn)備工作:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 配置數(shù)據(jù)庫(kù)連接
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:mysql@192.168.44.128:3306/test39"
# 配置取消數(shù)據(jù)庫(kù)跟蹤
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 配置數(shù)據(jù)庫(kù)輸出SQL語(yǔ)句
app.config['SQLALCHEMY_ECHO'] = True
# 創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象
db = SQLAlchemy(app)
class User(db.Model):
# 指定表名:默認(rèn)使用類名小寫
__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)
if __name__ == '__main__':
# 刪除所有表
# db.drop_all()
# # 創(chuàng)建所有表
# db.create_all()
# # 添加測(cè)試數(shù)據(jù)
# user1 = User(name='wang', email='wang@163.com', age=20)
# user2 = User(name='zhang', email='zhang@189.com', age=33)
# user3 = User(name='chen', email='chen@126.com', age=23)
# user4 = User(name='zhou', email='zhou@163.com', age=29)
# user5 = User(name='tang', email='tang@itheima.com', age=25)
# user6 = User(name='wu', email='wu@gmail.com', age=25)
# user7 = User(name='qian', email='qian@gmail.com', age=23)
# user8 = User(name='liu', email='liu@itheima.com', age=30)
# user9 = User(name='li', email='li@163.com', age=28)
# user10 = User(name='sun', email='sun@163.com', age=26)
#
# # 一次添加多條數(shù)據(jù)
# db.session.add_all([user1, user2, user3, user4, user5, user6, user7, user8, user9, user10])
# db.session.commit()
app.run(host="0.0.0.0",port=8000, debug=True)
2:進(jìn)行查詢操作:
# 1:查詢所有的用戶數(shù)據(jù):
users = User.query.all()
print(type(users))
print(users)
# 2:查詢一共有多少個(gè)用戶:
count = User.query.count()
print("一共有{}個(gè)人".format(count))
# 3:查詢第一個(gè)用戶信息:
user1 = User.query.first()
print("第一個(gè)用戶的信息是:{}".format(user1))
# 4:查詢id為4的三種方式:
#<方案一>:根據(jù)id查詢,返回模型類對(duì)象
user4 = User.query.get(4)
print("第四個(gè)用戶的信息是{}".format(user4))
# <方案二>:等值過(guò)濾器 關(guān)鍵字實(shí)參設(shè)置字段值 返回BaseQuery對(duì)象
user4 = User.query.filter_by(id=4).first()
print("第四個(gè)用戶的信息是{}".format(user4))
# <方案三>:使用復(fù)雜過(guò)濾器,返回BaseQuery對(duì)象
user4 = User.query.filter(User.id == 4).first()
print("第四個(gè)用戶的信息是{}".format(user4))
# 5:查詢用戶名字,開(kāi)始,結(jié)尾,包含n的用戶
user = User.query.filter(User.name.startswith('n')).all()
print("名字以n開(kāi)頭的用戶{}".format(user))
user = User.query.filter(User.name.endswith("n")).all()
print("名字以n結(jié)尾的用戶{}".format(user))
user = User.query.filter(User.name.contains("n")).all()
print("名字中包含n的用戶:{}".format(user))
# 6:查詢名字和郵箱都以li開(kāi)頭的所有用戶[2種方式]
users = User.query.filter(User.name.startswith('li'), User.email.startswith('li')).all()
print("查詢名字和郵箱都以li開(kāi)頭的所有用戶:{}".format(users))
users = User.query.filter(and_(User.name.startswith('li'), User.email.startswith('li'))).all()
print("查詢名字和郵箱都以li開(kāi)頭的所有用戶:{}".format(users))
# 7:查詢age是25或者email以com結(jié)尾的所有用戶
users = User.query.filter(or_(User.age==25, User.email.endswith('com'))).all()
print("age是25或者email以com結(jié)尾的所有用戶 : {}".format(users))
# 8: 查詢名字不等于wang的所有用戶
users = User.query.filter(User.name != "wang").all()
print("名字不等于wang的所有用戶: {}".format(users))
users= User.query.filter(not_(User.name=="wang")).all()
print("名字不等于wang的所有用戶: {}".format(users))
# 9: 查詢id是[1, 3, 5, 7, 9]的用戶
users = User.query.filter(User.id.in_([1, 3, 5, 7, 9])).all()
print("id是[1, 3, 5, 7, 9]的用戶: {}".format(users))
# 10:所有用戶先按年齡從小到大, 再按id從大到小排序, 取前5個(gè)
users = User.query.order_by(User.age, User.id.desc()).limit(5).all()
print("所有用戶先按年齡從小到大, 再按id從大到小排序, 取前5個(gè): {}".format(users))
# 11:查詢年齡從小到大第2-5位的數(shù)據(jù)
users = User.query.order_by(User.age).offset(1).limit(4).all()
print("查詢年齡從小到大第2-5位的數(shù)據(jù): {}".format(users))
# 12: 分頁(yè)查詢, 每頁(yè)3個(gè), 查詢第2頁(yè)的數(shù)據(jù) paginate(頁(yè)碼, 每頁(yè)條數(shù))
pn = User.query.paginate(2, 3)
print("總頁(yè)數(shù)是:", pn.pages)
print("當(dāng)前頁(yè):", pn.page)
print("當(dāng)前頁(yè)的數(shù)據(jù):", pn.items)
print("當(dāng)前頁(yè)的總條數(shù)", pn.total)
# 13: 查詢每個(gè)年齡段的人數(shù):(分組聚合)
data = db.session.query(User.age, func.count(User.id)).group_by(User.age).all()
for item in data:
print(item[0], item[1])
# 注意可以給列起別名,但是windows下會(huì)報(bào)錯(cuò),linux下不會(huì)報(bào)錯(cuò)。
# 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) # 建議通過(guò)label()方法給字段起別名, 以屬性方式獲取數(shù)據(jù)
# 14:只查詢所有人的姓名和郵箱,這種相當(dāng)于全表查詢,效率非常低。
data = db.session.query(User.name, User.email).all()
for item in data:
print(item.name, item.email)
# 15:優(yōu)化查詢
data = User.query.options(load_only(User.name, User.email)).all()
for item in data:
print(item.name, item.email)
return "index"
3:修改數(shù)據(jù):
1: 推薦采用方案二:
2: 一條語(yǔ)句, 被網(wǎng)絡(luò)IO影響程度低, 執(zhí)行效率更高
3:查詢和更新在一條語(yǔ)句中完成, 單條SQL具有原子性, 不會(huì)出現(xiàn)更新丟失問(wèn)題
4:會(huì)對(duì)滿足過(guò)濾條件的所有記錄進(jìn)行更新, 可以實(shí)現(xiàn)批量更新處理
方案一:先查詢?cè)俑拢?/p>
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 相關(guān)配置
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:mysql@192.168.44.128:3306/test39"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True
# 創(chuàng)建組件對(duì)象
db = SQLAlchemy(app)
# 構(gòu)建模型類 商品表
class Goods(db.Model):
__tablename__ = 't_good' # 設(shè)置表名
id = db.Column(db.Integer, primary_key=True) # 設(shè)置主鍵
name = db.Column(db.String(20), unique=True) # 商品名稱
count = db.Column(db.Integer) # 剩余數(shù)量
@app.route('/')
def purchase():
"""購(gòu)買商品"""
# 更新方式1: 先查詢后更新
# 缺點(diǎn): 并發(fā)情況下, 容易出現(xiàn)更新丟失問(wèn)題 (Lost Update)
# 1.執(zhí)行查詢語(yǔ)句, 獲取目標(biāo)模型對(duì)象
goods = Goods.query.filter(Goods.name == '方便面').first()
# 2.對(duì)模型對(duì)象的屬性進(jìn)行賦值 (更新數(shù)據(jù))
goods.count = goods.count - 1
# 3.提交會(huì)話
db.session.commit()
return "index"
if __name__ == '__main__':
# 刪除所有繼承自db.Model的表
db.drop_all()
# 創(chuàng)建所有繼承自db.Model的表
db.create_all()
# 添加一條測(cè)試數(shù)據(jù)
goods = Goods(name='方便面', count=1)
db.session.add(goods)
db.session.commit()
app.run(host="0.0.0.0", port=8000, debug=True)
方案二:配合查詢過(guò)濾器filter() 和 更新執(zhí)行器update() 進(jìn)行數(shù)據(jù)更新
Goods.query.filter(Goods.name == '方便面').update({'count': Goods.count - 1})
db.session.commit()
4:刪除數(shù)據(jù):
方案一:
# 方式1: 先查后刪除
goods = Goods.query.filter(Goods.name == '方便面').first()
# 刪除數(shù)據(jù)
db.session.delete(goods)
# 提交會(huì)話 增刪改都要提交會(huì)話
db.session.commit()
方案二:
# 方式2: delete子查詢
Goods.query.filter(Goods.name == '方便面').delete()
# 提交會(huì)話
db.session.commit()
三:高級(jí)機(jī)制:
1:刷新數(shù)據(jù):
1:Session 被設(shè)計(jì)為數(shù)據(jù)操作的執(zhí)行者, 會(huì)先將操作產(chǎn)生的數(shù)據(jù)保存到內(nèi)存中。
2: 在執(zhí)行 flush刷新操作 后, 數(shù)據(jù)操作才會(huì)同步到數(shù)據(jù)庫(kù)中。
3:隱式刷新操作:1:提交會(huì)話 2:查詢操作(包括更新和刪除中的子查詢)。
4:手動(dòng)刷新:session.flush()
刷新機(jī)制的理解:
答:刷新機(jī)制就是通過(guò)事務(wù),將SQl語(yǔ)句執(zhí)行一遍,然后將執(zhí)行結(jié)果存儲(chǔ)在變量中,但是數(shù)據(jù)庫(kù)做回滾操作。導(dǎo)致變量中有了新值,但是數(shù)據(jù)庫(kù)卻沒(méi)有改變。
goods = Goods(name='方便面', count=20)
db.session.add(goods)
# 主動(dòng)執(zhí)行flush操作, 立即執(zhí)行SQL操作(數(shù)據(jù)庫(kù)同步)
print(goods.id) # 此時(shí)是None
db.session.flush()
print(goods.id) # 此時(shí)是1
# Goods.query.count() # 查詢操作會(huì)自動(dòng)執(zhí)行flush操作
db.session.commit() # 提交會(huì)話會(huì)自動(dòng)執(zhí)行flush操作
2:多表查詢:
2.1:外鍵關(guān)聯(lián)查詢:
生成主表對(duì)象后,必須刷新數(shù)據(jù)庫(kù),否則后面無(wú)法使用主表對(duì)象的屬性。
1:主從表的定義:
# 用戶表 一 一個(gè)用戶可以有多個(gè)地址
class User(db.Model):
__tablename__ = 't_user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
# 地址表 多
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) # 定義外鍵
2:添加關(guān)聯(lián)數(shù)據(jù):
def index():
"""添加并關(guān)聯(lián)數(shù)據(jù)"""
user1 = User(name='張三')
db.session.add(user1)
db.session.flush() # 必須刷新,不然后面的user1.id是None
adr1 = Address(detail='中關(guān)村3號(hào)', user_id=user1.id)
adr2 = Address(detail='華強(qiáng)北5號(hào)', user_id=user1.id)
db.session.add_all([adr1, adr2])
db.session.commit()
return "index"
3:關(guān)聯(lián)查詢:
# 1.先根據(jù)姓名查找到主表主鍵
user1 = User.query.filter_by(name='張三').first()
# 2.再根據(jù)主鍵到從表查詢關(guān)聯(lián)地址
adrs = Address.query.filter_by(user_id=user1.id).all()
for adr in adrs:
print(adr.detail)
到此這篇關(guān)于Flask-Sqlalchemy的基本使用詳解的文章就介紹到這了,更多相關(guān)Flask-Sqlalchemy 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pyinstaller?pathex參數(shù)引發(fā)打包no?module?name異常
這篇文章主要為大家介紹了一個(gè)關(guān)于pyinstaller的?pathex?參數(shù)所引發(fā)的打包執(zhí)行報(bào)no?module?name的異常錯(cuò)誤解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
win10安裝tesserocr配置 Python使用tesserocr識(shí)別字母數(shù)字驗(yàn)證碼
這篇文章主要介紹了win10安裝tesserocr配置 Python使用tesserocr識(shí)別字母數(shù)字驗(yàn)證碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
pyqt5利用pyqtDesigner實(shí)現(xiàn)登錄界面
這篇文章主要為大家詳細(xì)介紹了pyqt5利用pyqtDesigner實(shí)現(xiàn)登錄界面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03
python如何獲取文件當(dāng)前位置和定位某個(gè)位置
這篇文章主要介紹了python如何獲取文件當(dāng)前位置和定位某個(gè)位置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
python批處理將圖片進(jìn)行放大實(shí)例代碼
最近處理一些規(guī)格不一的照片,需要修改成指定尺寸便于打印,下面這篇文章主要給大家介紹了關(guān)于python批處理將圖片進(jìn)行放大的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
python將一個(gè)英文語(yǔ)句以單詞為單位逆序排放的方法
今天小編就為大家分享一篇python將一個(gè)英文語(yǔ)句以單詞為單位逆序排放的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Python寫的創(chuàng)建文件夾自定義函數(shù)mkdir()
這篇文章主要介紹了Python寫的創(chuàng)建文件夾自定義函數(shù)mkdir(),文件夾操作是編程中經(jīng)常需要的,mkdir函數(shù)更是經(jīng)典中的經(jīng)典,需要的朋友可以參考下2014-08-08

