在關係型數據庫中,通常不會把所有數據都放在同一張表中,這樣做會額外佔用內存空間,
在關係列數據庫中通常用表關聯來解決數據庫。
常用的表關聯方式有三種:
- 一對一映射
如: 一個身份證對應一個人 - 一對多映射
如: 一個班級可以有多個學生 - 多對多映射
如: 一個學生可以報多個課程,一個課程可以有多個學生學習
一對一映射
-
語法
OneToOneField
class A(model.Model): ... class B(model.Model): 屬性 = models.OneToOneField(A)
-
用法示例
創建男人和妻子類# file : xxxxxxxx/models.py from django.db import models class Man(models.Model): '''男人模型類''' name = models.CharField('姓名', max_length=50) class Wife(models.Model): '''妻子模型類''' name = models.CharField("姓名", max_length=50) husband = models. (Man) # 增加一對一屬性
-
創始一對一的數據記錄
from . import models man1 = models.Man.objects.create(name='王先生') wife1 = models.Wife.objects.create(name='王夫人', husband=man1) # 關聯王老師 man2 = models.Man.objects.create(name='隔壁老王') # 一對一可以沒有數據對應的數據
-
一對一數據的相互獲取
在Wife
對象中,通過husband
屬性找到對應的Man
對象
在Author
對象中,通過wife
屬性找到對應的Wife
對象 -
正向查詢
直接通過關聯屬性查詢即可# 通過 wife 找 Man from . import models wife = models.Wife.objects.get(name='王夫人') print(wife.name, '的老公是', wife.husband.name)
-
反向查詢
通過反向關聯屬性查詢
反向關聯屬性爲實例對象.引用類名(小寫)
,如男人的反向引用爲男人對象.wife
當反向引用不存在時,則會觸發異常
# 通過 man.wife 關聯屬性 找 wife,如果沒有對應的wife則觸發異常 man1 = models.Man.objects.get(name='王先生') print(man1.name, '的妻子是', man1.wife.name) man2 = models.Man.objects.get(name='隔壁老王') try: print(man2.name, '的妻子是', man2.wife.name) except: print(man2.name, '還沒有妻子')
-
作用:
主要是解決常用數據與不常用數據的存儲問題,
把經常加載的一個數據放在主表中,不常用數據放在另一個副表中。
這樣在訪問主表數據時不需要加載副表中的數據以提高訪問速度提高效率和節省內存空間,
如經常把書的內容和書名建成兩張表,因爲在網站上經常訪問書名等信息,但不需要得到書的內容。
一對多映射
-
用法語法
ForeignKey
當一個A類對象可以關聯多個B類對象時class A(model.Model): ... class B(model.Model): a = models.ForeignKey(A)
-
外鍵類
ForeignKey
構造函數:ForeignKey(to, on_delete, **options)
參數to
關聯的主類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**options
可以是常用的字段選項如:null
,unique
等
-
示例
有二個出版社對應五本書的情況.
清華大學出版社
有書(C++,Java,Python)
北京大學出版社
有書(西遊記,水滸)-
定義一對多類
# file: one2many/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)
-
創建一對多的對象
# file: xxxxx/views.py from . import models pub1 = models.Publisher.objects.create(name='清華大學出版社') models.Book.objects.creat e(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)
-
查詢:
通過多查一
通過publisher
屬性查詢即可# 通過一本書找到對應的出版社 abook = models.Book.objects.get(id=1) print(abook.title, '的出版社是:', abook.publisher.name)
通過
一查多
通過book_set()
,管理器對象# 通過出版社查詢對應的書 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)
-
多對多映射
多對多表達對象之間多對多複雜關係,如: 每個人都有不同的學校(小學,初中,高中,…),每個學校都有不同的學生…
-
語法
ManyToManyField
-
示例
一個作者可以出版多本圖書
一本圖書可以被多名作者同時編寫class Author(models.Model): ... class Book(models.Model): ... authors = models.ManyToManyField(Author)
-
數據查詢
通過Book
查詢對應的所有的Authors
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所有並聯的書
-
示例:
多對多模型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) 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("顯示成功,請查看服務器端控制檯終端")
實際開發中,對於多對多的關係,在數據庫設計層面,一般都會使用中間表來處理。
中間表中以外鍵的方式(一對多)關聯兩個多方。
同樣的,在Django中也可以使用中間模型類來處理。