數據表關聯關系映射 Relationship Map
在關系型數據庫中,通常不會把所有數據都放在同一張表中,這樣做會額外占用內存空間,
在關系列數據庫中通常用表關聯來解決數據庫。
用的表關聯方式有三種:
一對一映射
如: 一個身份證對應一個人
一對多映射
如: 一個班級可以有多個學生
多對多映射
如: 一個學生可以報多個課程,一個課程可以有多個學生學習
一一對一映射
一對一是表示現實事物間存在的一對一的對應關系。
如:一個家庭只有一個戶主,一個男人有一個妻子,一個人有一個唯一的指紋信息等
1.語法:
在關聯的兩個類中的任何一個類中: class A(model.Model): ... class B(model.Model): 屬性 = models.OneToOneField(A)
2.用法
(1)創建作家和作家妻子類
# file : xxxxxxxx/models.py from django.db import models class Author(models.Model): '''作家模型類''' name = models.CharField('作家', max_length=50) class Wife(models.Model): '''作家妻子模型類''' name = models.CharField("妻子", max_length=50) author = models.OneToOneField(Author) # 增加一對一屬性
(2)查詢
- 在 Wife 對象中,通過 author 屬性找到對應的author對象
- 在 Author 對象中,通過 wife 屬性找到對應的wife對象
(3)創始一對一的數據記錄
from . import models author1 = models.Author.objects.create(name='王老師') wife1 = models.Wife.objects.create(name='王夫人', author=author1) # 關聯王老師 author2 = models.Author.objects.create(name='張老師') # 一對一可以沒有對應的數據
(4)一對一數據的相互獲取
1.正向查詢
直接通過關聯屬性查詢即可
# 通過 wife 找 author from . import models wife = models.Wife.objects.get(name='王夫人') print(wife.name, '的老公是', wife.author.name)
2.反向查詢
通過反向引用屬性查詢
反向引用屬性為實例對象,引用類名(小寫),如作家的反向引用為作家對象.wife
當反向引用不存在時,則會觸發異常
# 通過 author.wife 引用屬性 找 wife,如果沒有對應的wife剛觸發異常 author1 = models.Author.objects.get(name='王老師') print(author1.name, '的妻子是', author1.wife.name) author2 = models.Author.objects.get(name='張老師') try: print(author2.name, '的妻子是', author2.wife.name) except: print(author2.name, '還沒有妻子')
3.作用
主要是解決常用數據不常用數據的存儲問題,把經常加載的一個數據放在主表中,不常用數據放在另一個副表中,這樣在訪問主表數據時不需要加載副表中的數據以提高訪問速度提高效率和節省內存空間,如經常把書的內容和書名建成兩張表,因為在網站上經常訪問書名等信息,但不需要得到書的內容。
二一對多映射
一對多是表示現實事物間存在的一對多的對應關系。
如:一個學校有多個班級,一個班級有多個學生, 一本圖書只能屬於一個出版社,一個出版社允許出版多本圖書
1.用法:當一個A類對象可以關聯多個B類對象時
class A(model.Model): ... class B(model.Model): 屬性 = models.ForeignKey(多對一中"一"的模型類, ...)
2.外鍵類ForeignKey
- 構造函數:ForeignKey(to, on_delete, **options)
- 常用參數:
- on_delete
-
- models.CASCADE 級聯刪除。 Django模擬SQL約束ON DELETE CASCADE的行為,並刪除包含ForeignKey的對象。
- models.PROTECT 拋出ProtectedError 以阻止被引用對象的刪除;
- SET_NULL 設置ForeignKey null;只有null是True才有可能。
- SET_DEFAULT 將ForeignKey設置為其默認值;必須設置ForeignKey的默認值。
- ... 其它參請參考文檔 https://docs.djangoproject.com/en/1.11/ref/models/fields/#foreignkey ForeignKey部分
**options
可以是常用的字段選項如:
-
- null
- unique等
3.示例
有二個出版社對應五本書的情況.
1.清華大學出版社
有書
C++ Java Python
2.北京大學出版社
有書
西游記 水滸

1.定義一對多的類 # file: myorm/models.py from django.db import models class Publisher(models.Model): '''出版社''' name = models.CharField('名稱', max_length=50, unique=True) class Book(models.Model): title = models.CharField('書名', max_length=50) publisher = models.ForeignKey(Publisher, null=True) ---------------------- 2.創建一對多的對象 # file: xxxxx/views.py from . import models pub1 = models.Publisher.objects.create(name='清華大學出版社') models.Book.objects.create(title='C++', publisher=pub1) models.Book.objects.create(title='Java', publisher=pub1) models.Book.objects.create(title='Python', publisher=pub1) pub2 = models.Publisher.objects.create(name='北京大學出版社') models.Book.objects.create(title='西游記', publisher=pub2) models.Book.objects.create(title='水滸', publisher=pub2)
4.數據查詢
通過多查一
# 通過一本書找到對應的出版社 abook = models.Book.objects.get(id=1) print(abook.title, '的出版社是:', abook.publisher.name)
通過多查一
# 通過出版社查詢對應的書 pub1 = models.Publisher.objects.get(name='清華大學出版社') books = pub1.book_set.all() # 通過book_set 獲取pub1對應的多個Book數據對象 # books = models.Book.objects.filter(publisher=pub1) # 也可以采用此方式獲取 print("清華大學出版社的書有:") for book in books: print(book.title)
三多對多映射
多對多表達對象之間多對多復雜關系,如: 每個人都有不同的學校(小學,初中,高中,...),每個學校都有不同的學生...
1.語法
在關聯的兩個類中的任意一個類中,增加:
屬性 = models.ManyToManyField(MyModel)
2.示例
一個作者可以出版多本圖書 一本圖書可以被多名作者同時編寫 class Author(models.Model): xxxx xxxx class Book(models.Model): xxxx xxxx authors = models.ManyToManyField(Author)
3.數據查詢
通過Book查詢對應的所有的Authors
可以通過authors表示對應所有Author的查詢對象 book.authors.all() -> 獲取 book 對應的所有的author的信息 book.authors.filter(age__gt=80) -> 獲取book對應的作者中年齡大於80歲的作者的信息
通過Author查詢對應的所有的Books
Django會生成一個屬性 book_set 用於表示對對應的book的查詢對象相關操作 author.book_set.all() author.book_set.filter() author.book_set.create(...) # 創建新書並聯作用author author.book_set.add(book) # 添加已有的書為當前作者author author.book_set.clear() # 刪除author所有並聯的書 author.book_set.remove() # 刪除所author所有並聯的書

#多對多模型 class Author(models.Model): '''作家模型類''' name = models.CharField('作家', max_length=50) def __str__(self): return self.name class Book(models.Model): title = models.CharField('書名', max_length=50) author = models.ManyToManyField(Author, null=True) def __str__(self): return self.title ----------------------- #多對多視圖操作 from django.http import HttpResponse from . import models def many2many_init(request): # 創建兩人個作者 author1 = models.Author.objects.create(name='王老師') author2 = models.Author.objects.create(name='張老師') # 王老師和張老師同時寫了一本Python book11 = author1.book_set.create(title="Python") author2.book_set.add(book11) # # 張老師還寫了兩本書 book21 = author2.book_set.create(title="C") # 創建一本新書"C" book22 = author2.book_set.create(title="C++") # 創建一本新書"C++" return HttpResponse("初始化成功") def show_many2many(request): authors = models.Author.objects.all() for auth in authors: print("作者:", auth.name, '發出版了', auth.book_set.count(), '本書: ') for book in books: print(' ', book.title) print("----顯示書和作者的關系----") books = models.Book.objects.all() for book in books: auths = book.author.all() print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths])) return HttpResponse("顯示成功,請查看服務器端控制台終端") ------------------------ #多對多最終的SQL結果 mysql> select * from myorm2_author; +----+-----------+ | id | name | +----+-----------+ | 1 | 王老師 | | 1 | 張老師 | +----+-----------+ 2 rows in set (0.00 sec) mysql> select * from myorm2_book; +----+--------+ | id | title | +----+--------+ | 13 | Python | | 14 | C | | 15 | C++ | +----+--------+ 3 rows in set (0.00 sec) mysql> select * from myorm2_book_author; +----+---------+-----------+ | id | book_id | author_id | +----+---------+-----------+ | 17 | 13 | 11 | | 20 | 13 | 12 | | 18 | 14 | 12 | | 19 | 15 | 12 | +----+---------+-----------+ 4 rows in set (0.00 sec)