Django 7.Django框架 - 模型關係詳解
阿新 • • 發佈:2021-10-28
Django框架 - 模型關係詳解
Django 框架中,模型是資料層,也就是管理資料
在整個資料庫的設計中,還需要設計模型關係,也叫資料庫關係
關係概述
一對一
一個表中的一條資料對應另一個表中的一條資料
-- 例如使用者和使用者詳細資訊,在資料庫的設計中,應該分開儲存 -- 假設需要儲存的欄位有:id,使用者名稱,密碼,手機號,郵箱,頭像,年齡,性別,地址,學歷,身份證號... -- 大量欄位可以設定在一個表中進行資料儲存,但是效率不高,所以通常把這個資料表垂直分表 -- 即把表中的欄位進行分離,分到不同的表中儲存 -- 使用者表,儲存主要資訊 -- id,使用者名稱,密碼,手機號,郵箱,頭像,年齡,性別 -- 使用者詳情表,儲存其他資訊 -- id,地址,學歷,身份證號 -- 分表後,需要建立兩個表之間的關係,在使用者詳情表中增加欄位 uid,儲存當前行資料的使用者 id,即使用者表的主鍵 -- id,uid,地址,學歷,身份證號 -- 如果使用者表中的主鍵 id 在使用者詳情表中是唯一的,那麼此關係為一對一關係
一對多
一個表中的一個數據對應另一個表中的多個數據
-- 例如學生和班級
-- 學生表
-- id,姓名,年齡,手機號
-- 班級表
-- id,班級1,班級2,班級3
-- 在多的一端定義外來鍵欄位關聯一的一端
-- 一對多的關係非常常見
多對多
a表中的一個數據對應b表中的多個數據,同時b表中的一個數據也對應a表中的多個數據,即雙向一對多
-- 例如老師和班級 -- 老師1:班級1,班級3 -- 老師2:班級2,班級3 -- 老師3:班級1,班級2,班級4 -- 老師表 -- id 老師 1 老師1 2 老師2 3 老師3 -- 班級表 -- id 班級 1 班級1 2 班級2 3 班級3 4 班級4 -- 建立第三個表,描述表與表之間的關係 -- 老師_班級_關係表 -- id 老師tid 班級cid 1 老師1 班級1 2 老師1 班級3 3 老師2 班級2 4 老師2 班級3 5 老師3 班級1 6 老師3 班級2 7 老師3 班級4
關係的實現
- 邏輯關係
在需要的表中增加一個欄位,儲存另一個表中的主鍵,通過程式來控制和管理表的關係
- 物理關係
通過資料庫的外來鍵索引建立表的關係,這是在資料庫上物理形式建立的索引關係,不推薦使用此方法
缺點:外來鍵會導致表與表之間耦合,update和delete操作都會涉及相關聯的表,十分影響sql的效能,甚至會造成死鎖,高併發情況下容易造成資料庫效能下降,大資料高併發業務場景資料庫使用以效能優先
模型關係
一對一
一對一模型關係的定義
sid = models.OneToOneField(to,on_delete=models.CASCADE)
外來鍵欄位定義在要與主要資訊表相關聯的表中
# 學生類
class Stu(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
phone = models.CharField(man_length=11)
# 學生詳情類
class Stuinfo(models.Model):
# 建立一對一模型關係
sid = models.OneToOneField(Stu,on_delete=models.CASCADE)
addr = models.CharField(100)
team = models.CharField(20)
一對一模型關係的使用
# 新增
data = {'name':'messi','age':33,'phone':'3','address':'maj','team':'ulg'}
# 先新增Stu中的資料
stuobj = models.Stu()
stuobj.name = data['name']
stuobj.age = data['age']
stuobj.phone = data['phone']
stuobj.save()
# 再新增Stuinfo中的資料
# stuobj = models.Stu.objects.get(id=6)
sinfo = models.Stuinfo()
sinfo.address = data['address']
sinfo.team = data['team']
# Stuinfo模型類中,定義了外來鍵sid,新增時要指定sid的資料,並且要求是一個物件
sinfo.sid = stuobj
sinfo.save()
# 查詢
# 1.根據Stu物件獲取Stuinfo資料
stuobj = models.Stu.objects.get(id=5)
# 通過Stu物件直接獲取與自己關聯的Stuinfo物件
print(stuobj.stuinfo.address)
# 2.根據Stuinfo物件獲取Stu資料
sinfo = models.Stuinfo.objects.last()
# 通過被關聯的Stuinfo物件的sid欄位獲取Stu物件
print(sinfo.sid.name)
# 刪除
# 刪除Stu中的資料後,Stuinfo中對應的資料也被刪除
stuobj = models.Stu.objects.get(id=9)
stuobj.delete()
# 刪除Stuinfo中的資料後,Stu中對應的資料不受影響
sinfo = models.Stuinfo.objects.get(sid=4)
sinfo.delete()
一對多
一對多模型關係的定義
lid = models.ForeignKey(to,on_delete=models.CASCADE)
外來鍵欄位定義在多的一端
# 班級模型
class League(models.Model):
lname = models.CharField(max_length=20)
# 學生模型
class Stu(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
phone = models.CharField(max_length=11)
# 一對多,外來鍵欄位
lid = models.ForeignKey(to=League,on_delete=models.CASCADE,default='1')
# 如果Stu模型類已經建立,新增外來鍵欄位lid時,要求設定預設值
# 解決方法:1.註釋全部模型,重新建立
# 2.先建立League模型類,新增資料後,再為Stu模型類定義外來鍵欄位並設定預設值
一對多模型關係的使用
# 新增
# 建立League資料
l = models.League.objects.all()
print(l)
# 建立Stu資料時需要指定lid
data = {'name':'xavi','age':6,'phone':'37','lid':l[0]}
s = models.Stu(**data)
s.save()
# 查詢
# 1.根據League查詢Stu
l = models.League.objects.get(id=1)
print(l)
print(l.stu_set.all())
# 2.根據Stu查詢League
s = models.Stu.objects.all()
print(s[1].lid)
# 刪除
l = models.League.objects.get(id=1)
l.delete()
多對多
多對多模型關係的定義
models.ManyToManyField(to)
外來鍵欄位可以定義在任一表中
# 班級模型
class League(models.Model):
lname = models.CharField(max_length=20)
# 教師模型
class Teacher(models.Model):
tname = models.CharField(max_length=20)
# 多對多,外來鍵欄位
league = models.ManyToManyField('League')
多對多模型關係的使用
# 建立教師
t1 = models.Teacher(**{'tname':'愛因斯坦'})
t2 = models.Teacher(**{'tname':'狄拉克'})
t3 = models.Teacher(**{'tname':'海森堡'})
t1.save()
t2.save()
t3.save()
# 建立班級
l1 = models.League(**{'lname':'physics1'})
l2 = models.League(**{'lname':'physics2'})
l3 = models.League(**{'lname':'physics3'})
l4 = models.League(**{'lname':'physics4'})
l1.save()
l2.save()
l3.save()
l4.save()
# 建立關係
# 獲取所有教師和班級物件
ls = models.League.objects.all()
ts = models.Teacher.objects.all()
# 新增
# 給班級設定教師
ls[2].teacher_set.set([ts[0],ts[1]])
# 給教師設定班級
ts[0].league.set([ls[2],ls[3],ls[4]])
# 查詢
# 通過教師查詢班級
res = ls[2].teacher_set.all()
# 通過班級查詢教師
res = ts[1].league.all()
print(res)
# 刪除
# 刪除任意表中的資料,關係表中與其相關的關係將被同時刪除,另一個表不受影響
ls[2].delete()