Flask框架——ORM資料庫
一.通過SQLAlchemy(ORM)操作資料庫的流程
1.安裝擴充套件包, pip install flask_sqlalchemy 2.安裝資料庫驅動, pip install mysqldb / pymysql 3.導⼊SQLAlchemy類 4.配置資料庫的連結資訊等(可通過報錯獲取) 5.建立db = SQLAlchemy()物件,關聯app 6.編寫模型類,繼承⾃db.Model 7.編寫屬性,db.Colomn(型別,約束資訊)表示⼀列 8.操作(資料庫的增刪改查)
二.注意點
1.ORM不能建立資料庫,只能建立表 2.預設情況下,⽣成的表名稱是類名稱的⼩寫形式,如果需要指定,設定tablename 3.連結資料庫的格式: <協議名稱>://<⽤戶名>:<密碼>@<ip地址>:<端⼝>/<資料庫名> 如果使⽤的是mysqldb驅動,協議名: mysql 如果使⽤的是pymysql驅動,協議名: mysql+pymysql
三.建立資料表類(繼承db.Model)
1.設定表名: __tablename__ = 表名(字串) 2.設定欄位:欄位名 = db.Column(db.資料型別,約束) 3設定外來鍵:欄位名 = db.Column(db.資料型別,db.ForeignKey(關聯的表名.欄位名)) 注意:應設定__repr__方法,返回列印輸出的格式,否則按預設方式返回 例:
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # 指定資料庫的連結資訊 app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:
[email protected]:3306/basic12" # 這個配置將來會被禁用,設定為True或者False可以解除警告資訊,建議設定False app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False db = SQLAlchemy(app) # 角色模型類(一方) class Role(db.Model): __tablename__ = "roles" # db.Colomn()表示模型類的屬性, # 主鍵 id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return "<Role:%s,%s>" % (self.id, self.name) # 使用者模型類(多方) class User(db.Model): __tablename__ = "users" # db.Colomn()表示模型類的屬性, # 主鍵 id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) email = db.Column(db.String(64), unique=True) password = db.Column(db.String(64), unique=True) # 外來鍵,關聯的是Role表中的主鍵id role_id = db.Column(db.Integer, db.ForeignKey(Role.id)) # 如果繼承自object的類,使用__str__可以方便的查詢物件的輸出內容 # 如果繼承自db.Model的類,使用__repr__可以方便的查詢物件的輸出內容 def __repr__(self): return "<User:%s,%s,%s,%s>" % (self.id, self.name, self.email, self.password) print(User.query.all())
四.增刪改操作
方法 | 描述 |
---|---|
db.create_all() | 建立所有繼承⾃db.Model的類 |
db.drop_all() | 刪除所有繼承⾃db.Model的類 |
db.session.add(obj) | 新增物件 |
db.session.add_all([obj1,obj2,…]) | 新增多個物件 |
db.session.delete(obj) | 刪除物件 |
模型類.屬性名 = xxx | 修改物件 |
db.session.commit() | 提交會話 |
db.session.rollback() | 回滾 |
db.session.remove() | 移除會話 |
注意:所有使資料庫發生改變的操作都需要提交回話(db.session.commit())才會改變資料庫
五.查詢資料庫
格式:User.query.查詢過濾器.查詢執行器 1.常用查詢過濾器
過濾器 | 說明 |
---|---|
filter() | 把過濾器新增到原查詢上,返回一個新查詢 |
filter_by() | 把等值過濾器新增到原查詢上,返回一個新查詢 |
limit | 使用指定的值限定原查詢返回的結果 |
offset() | 偏移原查詢返回的結果,返回一個新查詢 |
order_by() | 根據指定條件對原查詢結果進行排序,返回一個新查詢 |
group_by() | 根據指定條件對原查詢結果進行分組,返回一個新查詢 |
2.常用執行過濾器
方法 | 說明 |
---|---|
all() | 以列表形式返回查詢的所有結果 |
first() | 返回查詢的第一個結果,如果未查到,返回None |
first_or_404() | 返回查詢的第一個結果,如果未查到,返回404 |
get() | 返回指定主鍵對應的行,如不存在,返回None |
get_or_404() | 返回指定主鍵對應的行,如不存在,返回404 |
count() | 返回查詢結果的數量 |
paginate() | 返回一個Paginate物件,它包含指定範圍內的結果 |
例:
查詢id為4的使用者[3種方式]
User.query.get(4)
User.query.filter_by(id = 4).first()
User.query.filter(User.id == 4).first()
查詢名字結尾字元為g的所有資料[開始/包含]
User.query.filter(User.name.endswith('g')).all()
User.query.filter(User.name.starstswith('g')).all()
User.query.filter(User.name.contains('g')).all()
查詢名字不等於wang的所有資料[2種方式]
查詢名字和郵箱都以 li 開頭的所有資料[2種方式]
User.query.filter(User.name.startswith('li'),User.email.startswith('li')).all()
User.query.filter(and_(User.name.startswith('li'),User.email.startswith('li'))).all()
查詢password是 `123456` 或者 `email` 以 `itheima.com` 結尾的所有資料
User.query.filter(or_(User.password == '123456',User.email.endswith('itheima.com'))).all()
查詢id為 [1, 3, 5, 7, 9] 的使用者列表
User.query.filter(User.id.in_([1,3,5,7,9])).all()
查詢name為liu的角色資料
user = User.query.filter(User.name == 'liu').first()
role = Role.query.filter(Role.id == user.role_id).first()
查詢所有使用者資料,並以郵箱排序
User.query.order_by(User.email).all()
User.query.order_by(User.email.desc()).all()
每頁3個,查詢第2頁的資料
paginate = User.query.paginate(page, per_page,Error_out)
paginate = User.query.paginate(2,3,False)
page: 哪一個頁
per_page: 每頁多少條資料
Error_out: False 查不到不報錯
pages: 共有多少頁
items: 當前頁數的所有物件
page: 當前頁
六.relationship關聯
1.一對多(有外來鍵連線的前提): 角色表:
class Role(db.Model):
__tablename__ = "roles"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
# 給Role新增關係屬性users, 查詢的方式: role.users
# 給User新增關係屬性role, 查詢的方式: user.role
users = db.relationship("User", backref="role", lazy="dynamic")
# 為了方便檢視物件輸出內容,重寫repr
def __repr__(self):
return "<Role:%s,%s>" % (self.id, self.name)
使用者表:
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
email = db.Column(db.String(32))
password = db.Column(db.String(32))
# 關鍵
role_id = db.Column(db.Integer, db.ForeignKey(Role.id))
# 為了方便檢視物件輸出內容,重寫repr
def __repr__(self):
return "<User:%s,%s,%s,%s>" % (self.id, self.name, self.email, self.password)
使用者表通過外來鍵繫結角色表,從而知道使用者的角色,設定relationship關聯後,可以直接通過屬性訪問。
格式: users = db.relationship("User", backref="role", lazy="dynamic")
引數 | 描述 |
---|---|
users | 可以設定任意字串,設定後users為角色類的一個屬性,role.users可直接訪問使用者表中與role物件相關聯的資料(role.users可檢視角色為role的使用者) |
backref | 設定反向關聯屬性,role也會成為使用者類的一個屬性,user.role可直接訪問角色表中與user物件相關聯的資料(user.role可檢視使用者user的角色) |
lazy | 使⽤關係屬性之後,預設會做⼦查詢(不管⽤不⽤的到都會查詢), 可以將lazy設定動態查詢 |
預設: lazy = “subquery”,不管⽤不⽤的到都會查詢 建議設定: lazy = “dynamic”,只有⽤到了才去查 格式:關聯屬性 = db.relationship(連線的資料庫類名, backref=反向繫結屬性)
(1)原始寫法:
user = User.query.get(1)
role = Role.query.get(user.role_id)
(2)快速查詢方式:
users = db.relationship("User",backref="role")
(設定後可通過users屬性直接訪問連線的User屬性)
user = User.query.get(1)
role = user.role
2.多對多: 多對多需要建立一箇中間表,將兩張表的主鍵儲存為中間表的外來鍵進行連線。 中間表格式:
表名稱 = db.Table( "表名稱",欄位1,欄位2 )
其中一方表:
db.relationship("模型類名",backref="屬性",secondary="中間表名")
例:
#學生,課程,中間表
student_course_tb = db.Table(
"student_course_tb",
db.Column("student_id",db.Integer,db.ForeignKey("students.id")),
db.Column("course_id",db.Integer,db.ForeignKey("courses.id"))
)
#編寫模型類
#學生模型
class Student(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(32))
#關係屬性
courses = db.relationship("Course",backref="students",secondary="student_course_tb")
#為了方便,檢視物件輸出內容
def __repr__(self):
return "<Student:%s,%s>"%(self.id,self.name)
#課程模型
class Course(db.Model):
__tablename__ = "courses"
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(32))
#為了方便,檢視物件輸出內容
def __repr__(self):
return "<Class:%s,%s>"%(self.id,self.name)
Student物件.courses可訪問關聯的課程,Course物件.students可訪問選該課的學生
七.資料庫遷移
1.目的:備份表的結構 2.過程: (1)安裝擴充套件:
pip install flask_migrate
pip install flask_script
(2)匯入類:
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
Manager:管理app Migrate:關聯app,db MigrateCommand:用manager新增操作命令使用MigrateCommand進行遷移(manager.add_command(“db”,MigrateCommand))
(3)終端指令: ⽣成遷移⽂件 (⼀次就好)
python xxx.py db init
將模型類,⽣成遷移指令碼 (重複執⾏)
python xxx.py db migrate -m '註釋'
將遷移指令碼更新到資料庫 (重複執⾏)
python xxx.py db upgrade / downgrade [version]
檢視所有的版本號
pythoh xxx.py db history
檢視當前版本號
python xxx.py db current
3.注意點: (1)資料庫遷移是為了備份表結構,⽽不是資料 (2)如果要備份資料,需要使⽤⼯具, ⽐如: navicat, mysqlworkbench等等⼯具 (3)如果進⾏降級的時候,會丟失資料,所以謹慎操作. 升級不會 例:
from flask import Flask
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 設定資料庫配置資訊
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:[email protected]:3306/basic12"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 建立SQLAlchemy物件,關聯app
db = SQLAlchemy(app)
# 通過Manager管理app
manager = Manager(app)
# - 使用Migrate,關聯app,db
Migrate(app, db)
# 給manager新增操作命令,使用MigrateCommand
manager.add_command("db", MigrateCommand)
# 模型類
class Student(db.Model):
__tablename__ = "students"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
age = db.Column(db.Integer)
@app.route('/')
def hello_world():
return "helloworld"
if __name__ == '__main__':
manager.run()
八.藍圖
1.目的: 為模組化開發⽽⽣
2.優點:弱耦合 實際開發中會用很多檢視和很多種類的檢視,寫在一個檔案中耦合度太高,所以使用可以使用藍圖分多模組編寫程式碼,然後將每個模組的藍圖物件在app上註冊。
3.操作步驟: (1)匯入藍圖:
from flask import Blueprint
(2)建立藍圖物件:
blue = Blueprint("藍圖名稱",__name__)
可選引數:
static_folder: 靜態⽂件夾
url_prefix: 藍圖資源訪問字首
template_folder: 藍圖模板⽂件夾
(3)使⽤藍圖裝飾檢視函式
@blue.route("/路徑")
(4)將藍圖物件註冊到app
app.register_blueprint(blue)