四川手機(jī)網(wǎng)站有哪些百度賬號(hào)注冊(cè)入口
SQLAlchemy 在 Flask 應(yīng)用中的使用和最佳實(shí)踐
- @[TOC](SQLAlchemy 在 Flask 應(yīng)用中的使用和最佳實(shí)踐)
- 模型的編寫
- **SQLAlchemy 中建立關(guān)聯(lián)**
- **利用 SQLAlchemy 中的關(guān)聯(lián)進(jìn)行查詢**
- **實(shí)現(xiàn)示例**
- backref與back_populates?
- **backref反向引用**
- **back_populates后填充**
- ****層面的關(guān)系****
- **數(shù)據(jù)庫層面的關(guān)系**
- **SQLAlchemy ORM 層面的關(guān)系**
- 模型的導(dǎo)入
SQLAlchemy 在 Flask 應(yīng)用中的使用和最佳實(shí)踐
- @[TOC](SQLAlchemy 在 Flask 應(yīng)用中的使用和最佳實(shí)踐)
- 模型的編寫
- **SQLAlchemy 中建立關(guān)聯(lián)**
- **利用 SQLAlchemy 中的關(guān)聯(lián)進(jìn)行查詢**
- **實(shí)現(xiàn)示例**
- backref與back_populates?
- **backref反向引用**
- **back_populates后填充**
- ****層面的關(guān)系****
- **數(shù)據(jù)庫層面的關(guān)系**
- **SQLAlchemy ORM 層面的關(guān)系**
- 模型的導(dǎo)入
在構(gòu)建 Python web 應(yīng)用時(shí),處理數(shù)據(jù)庫是一個(gè)不可避免的任務(wù)。SQLAlchemy 作為一個(gè)強(qiáng)大的 SQL 工具包和對(duì)象關(guān)系映射(ORM)系統(tǒng),為 Python 應(yīng)用提供了高效處理數(shù)據(jù)庫的能力。特別是在 Flask 這類框架中,SQLAlchemy 提供了一個(gè)直觀的方式來定義數(shù)據(jù)模型和執(zhí)行數(shù)據(jù)庫操作。
模型的編寫
在 SQLAlchemy 中,一個(gè)數(shù)據(jù)模型通常是通過定義一個(gè)類來創(chuàng)建的,這個(gè)類繼承自 db.Model
。模型類代表數(shù)據(jù)庫表,類中的屬性代表表中的列。例如:
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()class User(db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True, nullable=False)email = db.Column(db.String(120), unique=True, nullable=False)
在這個(gè)例子中,User
類代表一個(gè)用戶表,其中包含 ID、用戶名和電子郵件地址。
SQLAlchemy 中建立關(guān)聯(lián)
SQLAlchemy 允許在模型間建立一對(duì)多、多對(duì)一或多對(duì)多的關(guān)系。例如,一個(gè)店鋪擁有多個(gè)設(shè)備的一對(duì)多關(guān)系可以這樣定義:
class Store(db.Model):id = db.Column(db.Integer, primary_key=True)devices = db.relationship('Device', backref='store')class Device(db.Model):id = db.Column(db.Integer, primary_key=True)store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
利用 SQLAlchemy 中的關(guān)聯(lián)進(jìn)行查詢
有了關(guān)聯(lián)后,您可以輕松地在相關(guān)的模型之間進(jìn)行數(shù)據(jù)查詢。例如,要找到某個(gè)特定店鋪的所有設(shè)備,您可以使用以下代碼:
store = Store.query.get(some_store_id)
devices = store.devices
實(shí)現(xiàn)示例
假設(shè)您的模型之間的關(guān)系如下所述:
class GameRecord(db.Model):# ...device_id = db.Column(db.Integer, db.ForeignKey('device.id'))device = db.relationship('Device', backref='game_records')class Device(db.Model):# ...store_id = db.Column(db.Integer, db.ForeignKey('store.id'))store = db.relationship('Store', backref='devices')class Store(db.Model):# ...address = db.Column(db.String(200))
您可以這樣獲取游戲位置:
game_record = GameRecord.query.get(some_id)
game_location = game_record.device.store.address
backref與back_populates?
在 SQLAlchemy 中,backref
和 back_populates
都是用來定義模型間雙向關(guān)系的選項(xiàng),但它們?cè)谑褂蒙下杂胁煌@斫膺@兩個(gè)選項(xiàng)的區(qū)別有助于更好地組織和維護(hù)數(shù)據(jù)庫模型的關(guān)系。
backref反向引用
backref
是一種在定義關(guān)系時(shí)快捷創(chuàng)建反向引用的方式。- 當(dāng)您在一個(gè)模型(如
GameRecord
)中定義了一個(gè)關(guān)系(比如到User
),并使用了backref
,SQLAlchemy 會(huì)自動(dòng)在另一個(gè)模型(User
)中創(chuàng)建一個(gè)反向關(guān)系。 - 這意味著您無需在兩個(gè)模型中都定義關(guān)系,SQLAlchemy 會(huì)為您處理這部分。
例如,在 GameRecord
模型中定義 user
關(guān)系時(shí)使用 backref
:
class GameRecord(db.Model):# ...user = db.relationship('User', backref='game_records')
這將自動(dòng)在 User
模型中創(chuàng)建一個(gè) game_records
屬性,可以通過它訪問與該用戶相關(guān)聯(lián)的所有 GameRecord
實(shí)例。
back_populates后填充
back_populates
用于在兩個(gè)模型間明確地創(chuàng)建雙向關(guān)系。- 與
backref
不同,使用back_populates
需要在關(guān)聯(lián)的兩個(gè)模型中都明確地聲明關(guān)系。 - 這提供了更多的靈活性和清晰度,尤其是在復(fù)雜的關(guān)系中。
例如,設(shè)備(Device
)和店鋪(Store
)的關(guān)系可以使用 back_populates
定義:
在 Device
模型中:
class Device(db.Model):# ...store = db.relationship('Store', back_populates='devices')
在 Store
模型中:
class Store(db.Model):# ...devices = db.relationship('Device', back_populates='store')
這樣,Device
的每個(gè)實(shí)例都有一個(gè) store
屬性指向它所屬的 Store
,同時(shí)每個(gè) Store
實(shí)例都有一個(gè) devices
屬性指向所有屬于該店鋪的 Device
實(shí)例。
總而言之:
- 使用
backref
更為簡(jiǎn)便,但可能在某些情況下不夠明確。 - 使用
back_populates
提供了更明確的關(guān)系定義,特別是在復(fù)雜的模型關(guān)系中。 - 選擇使用哪一個(gè)取決于具體的應(yīng)用場(chǎng)景和個(gè)人編碼風(fēng)格。在大多數(shù)情況下,
backref
足以滿足需求,并且可以減少代碼量。
層面的關(guān)系
在 SQLAlchemy 中使用 db.relationship
建立的一對(duì)多關(guān)系(如您示例中的 devices = db.relationship('Device', backref='store', lazy=True)
)在數(shù)據(jù)庫層面是不直接體現(xiàn)的。這個(gè)關(guān)系存在于 SQLAlchemy ORM(對(duì)象關(guān)系映射)層面,用于在應(yīng)用程序中方便地處理和查詢數(shù)據(jù)庫記錄,但它不會(huì)直接映射為數(shù)據(jù)庫表中的某個(gè)字段或結(jié)構(gòu)。
數(shù)據(jù)庫層面的關(guān)系
- 在數(shù)據(jù)庫層面,一對(duì)多關(guān)系通常是通過外鍵實(shí)現(xiàn)的。例如,在
Device
表中,會(huì)有一個(gè)字段(如store_id
),作為外鍵指向Store
表的主鍵。 - 這種關(guān)系確保了數(shù)據(jù)的完整性和關(guān)聯(lián)性,但它本身并不提供直接的查詢機(jī)制。
SQLAlchemy ORM 層面的關(guān)系
db.relationship
是 SQLAlchemy 提供的高級(jí)抽象,允許您在兩個(gè)模型類之間建立關(guān)聯(lián)關(guān)系。- 這使得您可以用類似于操作普通 Python 對(duì)象的方式來處理數(shù)據(jù)庫記錄。例如,通過
store.devices
訪問一個(gè)特定店鋪的所有設(shè)備,或者通過device.store
訪問某個(gè)設(shè)備所屬的店鋪。 backref
參數(shù)在反向關(guān)系中添加了一個(gè)類似的便利屬性,這樣就可以從Device
實(shí)例輕松訪問其關(guān)聯(lián)的Store
實(shí)例。
總而言之:
- 數(shù)據(jù)庫層面的一對(duì)多關(guān)系是通過外鍵字段實(shí)現(xiàn)的。
- SQLAlchemy ORM 層面的
db.relationship
為這種關(guān)系提供了一個(gè)更為直觀和方便的操作接口,但它只存在于代碼層面,不直接映射到數(shù)據(jù)庫結(jié)構(gòu)中。 - 這種設(shè)計(jì)使得應(yīng)用程序的后端開發(fā)更加簡(jiǎn)潔和直觀,同時(shí)保持了數(shù)據(jù)庫的完整性和效率。
模型的導(dǎo)入
如果模型創(chuàng)建的順序不對(duì),可能會(huì)報(bào)錯(cuò),例如如下:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'device.store_id' could not find table 'store' with which to generate a foreign key to target column 'id'
問題出現(xiàn)在創(chuàng)建數(shù)據(jù)庫表時(shí),SQLAlchemy 無法找到 device
表中 store_id
字段引用的 store
表。錯(cuò)誤信息 sqlalchemy.exc.NoReferencedTableError
表明在嘗試創(chuàng)建外鍵關(guān)系時(shí),SQLAlchemy 無法找到被引用的表或列。
如果你確保你的表名都沒有問題,你可能需要考慮你的模型定義的順序又或者你是否正確導(dǎo)入了模型
例如,假設(shè)您的 Flask 應(yīng)用的入口點(diǎn)是 run.py
,您應(yīng)該檢查其中的導(dǎo)入語句和應(yīng)用初始化代碼。一個(gè)典型的 Flask 應(yīng)用結(jié)構(gòu)可能如下:
# run.pyfrom flask import Flask
from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = '您的數(shù)據(jù)庫連接'
db = SQLAlchemy(app)# 確保在 db.create_all() 調(diào)用之前導(dǎo)入所有模型
from models.store import Store
from models.device import Device
# ... 其他模型的導(dǎo)入 ...@app.route('/')
def index():return "Welcome to the app!"if __name__ == '__main__':db.create_all() # 在應(yīng)用上下文中創(chuàng)建所有數(shù)據(jù)庫表app.run(debug=True)
在這個(gè)示例中,Store
模型在 Device
模型之前導(dǎo)入,因?yàn)?Device
依賴于 Store
(store_id
字段是外鍵,指向 Store
表的主鍵)。如果 Store
和 Device
在不同的文件中定義,這種導(dǎo)入順序尤為重要。