1. 程式人生 > >Flask框架——ORM資料庫

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)