1. 程式人生 > 其它 >Django 7.Django框架 - 模型關係詳解

Django 7.Django框架 - 模型關係詳解

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()