Python?SQLAlchemy建立模型基礎(chǔ)關(guān)系模式過程詳解
使用SQLAlchemy建立模型之間的基礎(chǔ)關(guān)系模式
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 定義外鍵
定義外鍵:定義關(guān)系的第一步是創(chuàng)建外鍵。外鍵是(foreign key
)用來在 A 表存儲 B 表的主鍵值以便和 B 表建立聯(lián)系的關(guān)系字段。
因為外鍵只能存儲單一數(shù)據(jù)(標量),所以外鍵總是在 “多” 這一側(cè)定義,多篇文章屬于同 一個作者,所以我們需要為每篇文章添加外鍵存儲作者的主鍵值以指向 對應的作者。在 Article 模型中,我們定義一個 author_id
字段作為外鍵:
class Article(db.Model): ... author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
這個字段使用 db.ForeignKey
類定義為外鍵,傳入關(guān)系另一側(cè)的表名 和主鍵字段名,即 author.id
。實際的效果是將 article 表的 author_id
的值限制為 author 表的 id 列的值。它將用來存儲 author 表中記錄的主鍵值。
1.2 定義關(guān)系屬性
定義關(guān)系的第二步是使用關(guān)系函數(shù)定義關(guān)系屬性。關(guān)系屬性在關(guān)系 的出發(fā)側(cè)定義,即一對多關(guān)系的 “一” 這一側(cè)。一個作者擁有多篇文章, 在 Author 模型中,我們定義了一個 articles 屬性來表示對應的多篇文章:
class Author(db.Model): ... articles = db.relationship('Article')
這個屬性并沒有使用 Column 類聲明為列,而是使用了 db.relationship()
關(guān)系函數(shù)定義為關(guān)系屬性,因為這個關(guān)系屬性返回多個記錄,我們稱之為集合關(guān)系屬性。
relationship()
函數(shù)的第一個參數(shù) 為關(guān)系另一側(cè)的模型名稱,它會告訴 SQLAlchemy 將 Author
類與 Article
類建立關(guān)系。當這個關(guān)系屬性被調(diào)用時,SQLAlchemy 會找到關(guān)系另一側(cè) (即 article
表)的外鍵字段(即 author_id
),然后反向查詢 article
表中所有 author_id
值為當前表主鍵值(即 author.id
)的記錄,返回包含這些記錄的列表,也就是返回某個作者對應的多篇文章記錄。
1.3 建立關(guān)系
foo = Author(name='Foo') spam = Article(title='Spam') ham = Article(title='Ham')
建立關(guān)系有兩種方式,第一種方式是為外鍵字段賦值:
spam.author_id = 1 ham.author_id = 1
調(diào)用后,結(jié)果如下:
foo.articles # [<Article u'Spam'>, <Article u'Ham'>]
另一種方式是通過操作關(guān)系屬性,將關(guān)系屬性賦給實際的對象即可建立關(guān)系。
foo.articles.append(spam) foo.articles.append(ham)
1.4 建立雙向關(guān)系
我們在 Author
類中定義了集合關(guān)系屬性 articles
,用來獲取某個作者擁有的多篇文章記錄。在某些情況下,你也許希望能在 Article
類中定義 一個類似的 author
關(guān)系屬性,當被調(diào)用時返回對應的作者記錄,這類返回單個值的關(guān)系屬性被稱為 標量關(guān)系屬性。而這種兩側(cè)都添加關(guān)系屬性獲取對方記錄的關(guān)系我們稱之為 雙向關(guān)系(bidirectional relationship
)。
雙向關(guān)系并不是必須的,但在某些情況下會非常方便。雙向關(guān)系的建立很簡單,通過在關(guān)系的另一側(cè)也創(chuàng)建一個 relationship()
函數(shù),我們就可以在兩個表之間建立雙向關(guān)系。我們使用作家(Writer
)和書 (Book
)的一對多關(guān)系來進行演示:
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')
需要注意的是,我們只需要在關(guān)系的一側(cè)操作關(guān)系。當為 Book
對象的 writer
屬性賦值后,對應 Writer
對象的 books
屬性的返回值也會自動包含這個 Book
對象。反之,當某個 Writer
對象被刪除時,對應的 Book
對象的 writer
屬性被調(diào)用時的返回值也會被置為空(即 NULL
,會返回 None
)。
其他關(guān)系模式建立雙向關(guān)系的方式完全相同,在下面介紹不同的關(guān)系模式時我們會簡單說明。
1.5 使用 backref 簡化關(guān)系定義
在介紹關(guān)系函數(shù)的參數(shù)時,我們曾提到過,使用關(guān)系函數(shù)中的 backref
參數(shù)可以簡化雙向關(guān)系的定義。以一對多關(guān)系為例,backref
參數(shù)用來自動為關(guān)系另一側(cè)添加關(guān)系屬性,作為反向引用(back reference
),賦予的值會作為關(guān)系另一側(cè)的關(guān)系屬性名稱。
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
定義雙向關(guān)系。
2.多對一
一對多關(guān)系反過來就是多對一關(guān)系,這兩種關(guān)系模式分別從不同的視角出發(fā)。
我們在前面介紹過,關(guān)系屬性在關(guān)系模式的出發(fā)側(cè)定義。當出發(fā)點在 “多” 這一側(cè)時,我們希望在 Citizen
類中添加一個關(guān)系屬性 city
來獲取對應的城市對象,因為這個關(guān)系屬性返回單個值,我們稱之為標量關(guān)系屬性。在定義關(guān)系時,外鍵總是在 “多” 這一側(cè)定義,所以在多對一關(guān)系中外鍵和關(guān)系屬性都定義在 “多” 這一側(cè),即 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
關(guān)系屬性是一個標量屬性(返回單一數(shù)據(jù))。當 Citizen.city
被調(diào)用時,SQLAlchemy
會根據(jù)外鍵字段 city_id
存儲的值查找對應的 City
對象并返回,即居民記錄對應的城市記錄。
當建立雙向關(guān)系時,如果不使用 backref
,那么一對多和多對一關(guān)系 模式在定義上完全相同,這時可以將一對多和多對一視為同一種關(guān)系模式。在后面我們通常都會為一對多或多對一建立雙向關(guān)系,這時將弱化這兩種關(guān)系的區(qū)別,一律稱為一對多關(guān)系。
3.一對一
一對一關(guān)系實際上是通過建立雙向關(guān)系的一對多關(guān)系的基礎(chǔ)上轉(zhuǎn)化而來。我們要確保關(guān)系兩側(cè)的關(guān)系屬性都是標量屬性,都只返回單個值,所以要在定義集合屬性的關(guān)系函數(shù)中將 uselist
參數(shù)設(shè)為 False
,這時一對多關(guān)系將被轉(zhuǎn)換為一對一關(guān)系。
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.多對多
我們將使用學生和老師來演示多對多關(guān)系:每個學生有多個老師, 而每個老師有多個學生。
在一對多關(guān)系中,我們可以在 “多” 這一側(cè)添加外鍵指向 “一” 這一 側(cè),外鍵只能存儲一個記錄,但是在多對多關(guān)系中,每一個記錄都可以與關(guān)系另一側(cè)的多個記錄建立關(guān)系,關(guān)系兩側(cè)的模型都需要存儲一組外鍵。
在 SQLAlchemy
中,要想表示多對多關(guān)系,除了關(guān)系兩側(cè)的模型外,我們還需要創(chuàng)建一個關(guān)聯(lián)表(association table
)。關(guān)聯(lián)表不存儲數(shù)據(jù),只用來存儲關(guān)系兩側(cè)模型的外鍵對應關(guān)系。
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))
當我們需要查詢某個學生記錄的多個老師時,我們先通過學生和關(guān)聯(lián)表的一對多關(guān)系查找所有包含該學生的關(guān)聯(lián)表記錄,然后就可以從這 些記錄中再進一步獲取每個關(guān)聯(lián)表記錄包含的老師記錄。
我們在 Student
類中定義一個 teachers
關(guān)系屬性用來獲取老師集合。 在多對多關(guān)系中定義關(guān)系函數(shù),除了第一個參數(shù)是關(guān)系另一側(cè)的模型名稱外,我們還需要添加一個 secondary
參數(shù),把這個值設(shè)為關(guān)聯(lián)表的名稱。
為了便于實現(xiàn)真正的多對多關(guān)系,我們需要建立雙向關(guān)系。建立雙向關(guān)系后,多對多關(guān)系會變得更加直觀。在 Student
類上的 teachers
集合 屬性會返回所有關(guān)聯(lián)的老師記錄,而在 Teacher
類上的 students
集合屬性 會返回所有相關(guān)的學生記錄。
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')
關(guān)聯(lián)表由 SQLAlchemy 接管,它會幫我們管理這個表:我們只需要像往常一樣通過操作關(guān)系屬性來建立或解除關(guān)系,SQLAlchemy 會自動在關(guān)聯(lián)表中創(chuàng)建或刪除對應的關(guān)聯(lián)表記錄,而不用手動操作關(guān)聯(lián)表。
到此這篇關(guān)于Python SQLAlchemy建立模型基礎(chǔ)關(guān)系模式過程詳解的文章就介紹到這了,更多相關(guān)Python SQLAlchemy建立模型基礎(chǔ)關(guān)系內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python環(huán)境Pillow( PIL )圖像處理工具使用解析
這篇文章主要介紹了Python環(huán)境Pillow( PIL )圖像處理工具使用解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-09-09