網站首頁 編程語言 正文
使用SQLAlchemy建立模型之間的基礎關系模式
1.一對多
class Author(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) phone = db.Column(db.String(20)) class Article(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(50), index=True) body = db.Column(db.Text)
1.1 定義外鍵
定義外鍵:定義關系的第一步是創建外鍵。外鍵是(foreign key
)用來在 A 表存儲 B 表的主鍵值以便和 B 表建立聯系的關系字段。
因為外鍵只能存儲單一數據(標量),所以外鍵總是在 “多” 這一側定義,多篇文章屬于同 一個作者,所以我們需要為每篇文章添加外鍵存儲作者的主鍵值以指向 對應的作者。在 Article 模型中,我們定義一個 author_id
字段作為外鍵:
class Article(db.Model): ... author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
這個字段使用 db.ForeignKey
類定義為外鍵,傳入關系另一側的表名 和主鍵字段名,即 author.id
。實際的效果是將 article 表的 author_id
的值限制為 author 表的 id 列的值。它將用來存儲 author 表中記錄的主鍵值。
1.2 定義關系屬性
定義關系的第二步是使用關系函數定義關系屬性。關系屬性在關系 的出發側定義,即一對多關系的 “一” 這一側。一個作者擁有多篇文章, 在 Author 模型中,我們定義了一個 articles 屬性來表示對應的多篇文章:
class Author(db.Model): ... articles = db.relationship('Article')
這個屬性并沒有使用 Column 類聲明為列,而是使用了 db.relationship()
關系函數定義為關系屬性,因為這個關系屬性返回多個記錄,我們稱之為集合關系屬性。
relationship()
函數的第一個參數 為關系另一側的模型名稱,它會告訴 SQLAlchemy 將 Author
類與 Article
類建立關系。當這個關系屬性被調用時,SQLAlchemy 會找到關系另一側 (即 article
表)的外鍵字段(即 author_id
),然后反向查詢 article
表中所有 author_id
值為當前表主鍵值(即 author.id
)的記錄,返回包含這些記錄的列表,也就是返回某個作者對應的多篇文章記錄。
1.3 建立關系
foo = Author(name='Foo') spam = Article(title='Spam') ham = Article(title='Ham')
建立關系有兩種方式,第一種方式是為外鍵字段賦值:
spam.author_id = 1 ham.author_id = 1
調用后,結果如下:
foo.articles # [<Article u'Spam'>, <Article u'Ham'>]
另一種方式是通過操作關系屬性,將關系屬性賦給實際的對象即可建立關系。
foo.articles.append(spam) foo.articles.append(ham)
1.4 建立雙向關系
我們在 Author
類中定義了集合關系屬性 articles
,用來獲取某個作者擁有的多篇文章記錄。在某些情況下,你也許希望能在 Article
類中定義 一個類似的 author
關系屬性,當被調用時返回對應的作者記錄,這類返回單個值的關系屬性被稱為 標量關系屬性。而這種兩側都添加關系屬性獲取對方記錄的關系我們稱之為 雙向關系(bidirectional relationship
)。
雙向關系并不是必須的,但在某些情況下會非常方便。雙向關系的建立很簡單,通過在關系的另一側也創建一個 relationship()
函數,我們就可以在兩個表之間建立雙向關系。我們使用作家(Writer
)和書 (Book
)的一對多關系來進行演示:
class Writer(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) books = db.relationship('Book', back_populates='writer') class Book(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(50), index=True) writer_id = db.Column(db.Integer, db.ForeignKey('writer.id')) writer = db.relationship('Writer', back_populates='books')
需要注意的是,我們只需要在關系的一側操作關系。當為 Book
對象的 writer
屬性賦值后,對應 Writer
對象的 books
屬性的返回值也會自動包含這個 Book
對象。反之,當某個 Writer
對象被刪除時,對應的 Book
對象的 writer
屬性被調用時的返回值也會被置為空(即 NULL
,會返回 None
)。
其他關系模式建立雙向關系的方式完全相同,在下面介紹不同的關系模式時我們會簡單說明。
1.5 使用 backref 簡化關系定義
在介紹關系函數的參數時,我們曾提到過,使用關系函數中的 backref
參數可以簡化雙向關系的定義。以一對多關系為例,backref
參數用來自動為關系另一側添加關系屬性,作為反向引用(back reference
),賦予的值會作為關系另一側的關系屬性名稱。
class Singer(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) songs = db.relationship('Song', backref='singer') class Song(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), index=True) singer_id = db.Column(db.Integer, db.ForeignKey('singer.id'))
盡管使用 backref
非常方便,但通常來說 “顯式好過隱式”,所以我們應該盡量使用 back_populates
定義雙向關系。
2.多對一
一對多關系反過來就是多對一關系,這兩種關系模式分別從不同的視角出發。
我們在前面介紹過,關系屬性在關系模式的出發側定義。當出發點在 “多” 這一側時,我們希望在 Citizen
類中添加一個關系屬性 city
來獲取對應的城市對象,因為這個關系屬性返回單個值,我們稱之為標量關系屬性。在定義關系時,外鍵總是在 “多” 這一側定義,所以在多對一關系中外鍵和關系屬性都定義在 “多” 這一側,即 City
類中。
class Citizen(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) city_id = db.Column(db.Integer, db.ForeignKey('city.id')) city = db.relationship('City') class City(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True)
這時定義的 city
關系屬性是一個標量屬性(返回單一數據)。當 Citizen.city
被調用時,SQLAlchemy
會根據外鍵字段 city_id
存儲的值查找對應的 City
對象并返回,即居民記錄對應的城市記錄。
當建立雙向關系時,如果不使用 backref
,那么一對多和多對一關系 模式在定義上完全相同,這時可以將一對多和多對一視為同一種關系模式。在后面我們通常都會為一對多或多對一建立雙向關系,這時將弱化這兩種關系的區別,一律稱為一對多關系。
3.一對一
一對一關系實際上是通過建立雙向關系的一對多關系的基礎上轉化而來。我們要確保關系兩側的關系屬性都是標量屬性,都只返回單個值,所以要在定義集合屬性的關系函數中將 uselist
參數設為 False
,這時一對多關系將被轉換為一對一關系。
class Country(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True) capital = db.relationship('Capital', uselist=False) class Capital(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30), unique=True) country_id = db.Column(db.Integer, db.ForeignKey('country.id')) country = db.relationship('Country')
4.多對多
我們將使用學生和老師來演示多對多關系:每個學生有多個老師, 而每個老師有多個學生。
在一對多關系中,我們可以在 “多” 這一側添加外鍵指向 “一” 這一 側,外鍵只能存儲一個記錄,但是在多對多關系中,每一個記錄都可以與關系另一側的多個記錄建立關系,關系兩側的模型都需要存儲一組外鍵。
在 SQLAlchemy
中,要想表示多對多關系,除了關系兩側的模型外,我們還需要創建一個關聯表(association table
)。關聯表不存儲數據,只用來存儲關系兩側模型的外鍵對應關系。
association_table = db.Table( 'association', db.Column('student_id', db.Integer, db.ForeignKey('student.id')), db.Column('teacher_id', db.Integer, db.ForeignKey('teacher.id')) ) class Student(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) grade = db.Column(db.String(20)) teachers = db.relationship('Teacher', secondary=association_table, back_populates='students') class Teacher(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(70), unique=True) office = db.Column(db.String(20))
當我們需要查詢某個學生記錄的多個老師時,我們先通過學生和關聯表的一對多關系查找所有包含該學生的關聯表記錄,然后就可以從這 些記錄中再進一步獲取每個關聯表記錄包含的老師記錄。
我們在 Student
類中定義一個 teachers
關系屬性用來獲取老師集合。 在多對多關系中定義關系函數,除了第一個參數是關系另一側的模型名稱外,我們還需要添加一個 secondary
參數,把這個值設為關聯表的名稱。
為了便于實現真正的多對多關系,我們需要建立雙向關系。建立雙向關系后,多對多關系會變得更加直觀。在 Student
類上的 teachers
集合 屬性會返回所有關聯的老師記錄,而在 Teacher
類上的 students
集合屬性 會返回所有相關的學生記錄。
class Student(db.Model): ... teachers = db.relationship('Teacher', secondary=association_table, back_populates='students') class Teacher(db.Model): ... students = db.relationship('Student', secondary=association_table, back_populates='teachers')
關聯表由 SQLAlchemy 接管,它會幫我們管理這個表:我們只需要像往常一樣通過操作關系屬性來建立或解除關系,SQLAlchemy 會自動在關聯表中創建或刪除對應的關聯表記錄,而不用手動操作關聯表。
原文鏈接:https://blog.csdn.net/be_racle/article/details/127134603
相關推薦
- 2022-11-05 Flutter實現一個支持漸變背景的Button示例詳解_Android
- 2022-09-16 python?playwright之元素定位示例詳解_python
- 2022-08-02 Python+Selenium實現瀏覽器標簽頁的切換_python
- 2022-05-22 Nginx圖片服務器配置之后圖片訪問404的問題解決_nginx
- 2022-07-20 nginx?添加http_stub_status_module模塊_nginx
- 2022-10-10 python讀取和保存為excel、csv、txt文件及對DataFrame文件的基本操作指南_py
- 2022-08-30 Springcloud--Nacos服務治理
- 2022-08-04 Python并發編程之IO模型_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支