看了第四遍Miguel Grinberg寫的《Flask Web》一書,前面部分都非常順利,但到了關注者這一章,被多對多關係卡住了。在寫本篇博客時我腦子裏還是一團漿糊,邊寫邊想吧。
在說多對多關係之前,先回顧一下一對多關係
一對多
拿之前的章節來說,有兩張表,分別是Role表和User表。
Role表:普通用戶,管理員
User表:用戶名,郵件,地址,電話。。。
我們知道,一個用戶只能有一種角色,但一種角色可以有多個用戶。
即:一個角色對應多個用戶。
粗略地使用SQLAlchemy構建一對多關係就是
class Role(db.Model):
...
users = db.relationship('User', backref='role')
class User(db.Model):
...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
- 外鍵的值就是另一張表的主鍵值,通過這樣一種相同值將2張表聯結起來
- 關係表的設計:保證一類一表,用相同值(外鍵)聯結在一起
上面的代碼表示,我們在User表中添加了外鍵(role_id列),它的值指向roles表的主鍵(id列),這樣,user可以通過role_id的值來獲取其角色內容
多對多關係
先來看多對多關係的實際應用:學生選課
一名學生可以選擇多門課,
一門課也同時有多名學生選擇
學生選課就是一個多對多的關係。你怎麼用student表和class表來表示這個多對多的關係?先想想看怎麼加這個外鍵,因爲外鍵纔是聯結兩表的重要部分。
學生表
學號 | 姓名 |
---|---|
1 | 甲 |
2 | 乙 |
3 | 丙 |
課程表
課程號 | 課程 |
---|---|
101 | 語 |
102 | 數 |
103 | 外 |
如果在學生表裏加個class_id(課程號)
學號 | 姓名 | 課程號 |
---|---|---|
1 | 甲 | 101 |
2 | 乙 | 101 |
3 | 丙 | 102 |
你會發現,一名學生只能選擇一門課,一門課可以被多個學生選擇。
反之,如果你在課程表里加個學號,那也只能表示,一門課只有一名學生。所以只有2張表的話,外鍵是不好加進去的。
解決方法:添加第3張表,我們稱之爲“”關聯表“”。
關聯表學號 | 關聯表課程號 |
---|---|
1 | 101 |
1 | 102 |
2 | 101 |
3 | 102 |
2 | 103 |
這他媽不就是一一對應的表嘛!!(滑稽)
儘管這有點滑稽,但是它卻能完美解決我們的問題
- 一個學生有多個記錄,但一個記錄只能屬於一個學生。
- 一個課程有多個記錄,但一個記錄也只能有一個課程
這就是關聯表的作用,將多對多拆分成兩個一對多。
SQLAlchemy實現:
幾點說明
1.關聯表就是一張簡單的表,不是模型,所以注意寫法
2.多對多關係可以在任意一側定義關係,這裏是在student表裏定義
3.secondary參數爲關聯表名
4.backref會自動處理另一側的反向引用,所以你看class表那麼簡潔
現在查詢就變的簡單了。
要查小明選的所有課:小明.classes.all()
要查所有上語文課的學生:語文.students.all()
如果小明再選一門數學:小明.classes.add(數學)
如果小明退選一門化學:小明.classes.remove(化學)