基于Django ORM、一對一、一對多、多對多的全面講解
上篇博客也提到這些知識點(diǎn),可能大家還是不太清楚,這篇博客為大家詳細(xì)講解ORM中的幾個知識點(diǎn)
1.1首先我們先看一個小案例:
#_*_coding:utf-8_*_ from django.db import models # Create your models here. class Colors(models.Model): colors=models.CharField(max_length=10) #藍(lán)色 def __str__(self): return self.colors class Ball(models.Model): color=models.OneToOneField("Colors") #與顏色表為一對一,顏色表為母表 description=models.CharField(max_length=10) #描述 def __str__(self): return self.description class Clothes(models.Model): color=models.ForeignKey("Colors") #與顏色表為外鍵,顏色表為母表 description=models.CharField(max_length=10) #描述 def __str__(self): return self.description class Child(models.Model): name=models.CharField(max_length=10) #姓名 favor=models.ManyToManyField('Colors') #與顏色表為多對多
先來區(qū)分一下什么是一對一、多對多
一對一:子表從母表中選出一條數(shù)據(jù)一一對應(yīng),母表中選出來一條就少一條,子表不可以再選擇母表中已被選擇的那條數(shù)據(jù)
一對多:子表從母表中選出一條數(shù)據(jù)一一對應(yīng),但母表的這條數(shù)據(jù)還可以被其他子表數(shù)據(jù)選擇
共同點(diǎn)是在admin中添加數(shù)據(jù)的話,都會出現(xiàn)一個select選框,但只能單選,因?yàn)椴徽撘粚σ贿€是一對多,自己都是“一”
多對多總結(jié):
比如有多個孩子,和多種顏色、
每個孩子可以喜歡多種顏色,一種顏色可以被多個孩子喜歡,對于雙向均是可以有多個選擇
應(yīng)用場景
一對一:一般用于某張表的補(bǔ)充,比如用戶基本信息是一張表,但并非每一個用戶都需要有登錄的權(quán)限,不需要記錄用戶名和密碼,此時,合理的做法就是新建一張記錄登錄信息的表,與用戶信息進(jìn)行一對一的關(guān)聯(lián),可以方便的從子表查詢母表信息或反向查詢
外鍵:有很多的應(yīng)用場景,比如每個員工歸屬于一個部門,那么就可以讓員工表的部門字段與部門表進(jìn)行一對多關(guān)聯(lián),可以查詢到一個員工歸屬于哪個部門,也可反向查出某一部門有哪些員工
多對多:如很多公司,一臺服務(wù)器可能會有多種用途,歸屬于多個產(chǎn)品線當(dāng)中,那么服務(wù)器與產(chǎn)品線之間就可以做成對多對,多對多在A表添加manytomany字段或者從B表添加,效果一致
一對一
查:
#子表查詢母表,找到紅球?qū)?yīng)的顏色 #寫法1: print(models.Ball.objects.get(description="紅球").color.colors) #返回紅,通過子表查詢母表,寫法:"子表對象.母表表名的小寫.母表字段名" ;通過Ball表查到description為"紅球",查找到對應(yīng)colors #寫法2,反向從母表入手: print(models.Colors.objects.get(ball__description="紅球").colors) #返回紅,通過子表查詢母表,但形式上是從母表對象自身直接獲取字段,寫法:"母表.objects.get(子表名小寫__子表字段="xxx").母表字段名" ;效果和上邊完全一致,另一種形式 #母表查詢子表,找到紅色對應(yīng)的球的名字 #寫法1: print(models.Colors.objects.get(colors="紅").ball.description) #返回紅球,通過母表查詢子表,寫法:"母表對象.子表表名的小寫.子表字段名";找到顏色為紅色的Ball的description #寫法2,反向從子表入手: print(models.Ball.objects.get(color__colors="紅").description) #返回紅球,通過母表查詢子表,但形式上是從子表對象自身直接獲取字段,寫法:"子表.objects.get(一對一的子表字段__母表字段="xxx").子表字段";效果和上邊完全一致,另一種形式
增:
#添加一種顏色黑,并添加黑球 color_obj=models.Colors.objects.create(colors="黑") #先在母表中創(chuàng)建顏色,并實(shí)例化給顏色表對象 models.Ball.objects.create(color=color_obj,description="黑球") #更新Ball表,color字段為顏色表對象,添加description字段
備注:增添數(shù)據(jù)的3種常用方式
#增添數(shù)據(jù)的三種寫法: #寫法1: color_obj=models.Colors.objects.create(colors="黑") models.Ball.objects.create(color=color_obj,description="黑球") #寫法1補(bǔ)充: color_id=models.Colors.objects.create(colors="黑").id models.Ball.objects.create(color_id=color_id,description="黑球") #寫法2: color_obj=models.Colors.objects.create(colors="黑") ball_obj=models.Ball(color=color_obj,description="黑球") ball_obj.save() #寫法3(字典導(dǎo)入): color_obj=models.Colors.objects.create(colors="黑") ball_dic={'description':"黑球"} models.Ball.objects.create(color=color_obj,**ball_dic)
改:
color_obj=models.Colors.objects.get(colors="黑") #.get()等同于.filter().first() color_obj.colors="灰" color_obj.save() models.Ball.objects.filter(description="黑球").update(color=color_obj,description="灰球") #update(),delete()是QuerySet的方法
備注:修改數(shù)據(jù)的常見方式
#更新一條數(shù)據(jù) color_obj=models.Colors.objects.get(colors="黑") color_obj.colors="灰" color_obj.save() #更新多條數(shù)據(jù),把滿足條件的球的description都變?yōu)榛仪? #寫法1: models.Ball.objects.filter(color__colors="紅").update(description="灰球") #寫法2: up_dic={"description":"灰球"} models.Ball.objects.filter(id__gt=0).update(**up_dic)
刪:
models.Ball.objects.get(description="灰球").delete() #對象和QuerySet都有方法delete() models.Colors.objects.filter(colors="灰").delete() models.Colors.objects.all().delete() #清空一張表
一對多(外鍵)
查:
#外鍵表聯(lián)合查詢: #外鍵子表查詢母表,與一對一子表查詢母表形式一致 #找到紅褲衩所屬的顏色表中的顏色--返回:紅 #寫法1: print(models.Clothes.objects.get(description="小虎哥").color.colors) #返回紅,通過子表查詢母表,寫法:"子表對象.母表表名的小寫.母表字段名" ;通過Clothes表查到description為"小虎哥",查找到對應(yīng)colors #寫法2,反向從母表入手: print(models.Colors.objects.get(clothes__description="小虎哥").colors) #返回紅,通過子表查詢母表,但形式上是從母表對象自身直接獲取字段,寫法:"母表.objects.get(子表名小寫__子表字段="xxx").母表字段名" ;效果和上邊完全一致,另一種形式 #外鍵母表查詢子表,與一對一形式不同,因?yàn)槟副頌?多",不能像一對一一樣通過.get().子表.子表字段的方式獲取,但與多對多母表查詢子表一致 #找到顏色為紅的所有服裝--返回:[<Clothes: 大美女>, <Clothes: 小虎哥>] #寫法1: color_obj=models.Colors.objects.get(colors="紅") print(color_obj.clothes_set.all()) #注意:子表小寫_set的寫法,它實(shí)際上是一個QuerySet,可以用update,delete,all,filter等方法 #寫法2: print(models.Clothes.objects.filter(color=models.Colors.objects.get(colors="紅"))) #寫法2簡便寫法(推薦): print(models.Clothes.objects.filter(color__colors="紅")) #寫法:filter(子表外鍵字段__母表字段='過濾條件') #寫法3: color_id=models.Colors.objects.get(colors="紅").id #通過母表獲取到顏色為紅的id print(models.Clothes.objects.filter(color_id=color_id)) #filter得到QuerySet,寫法:filter(子表外鍵字段_母表主鍵=母表主鍵對象)
備注:通過QuerySet的.values()方法,將QuerySet轉(zhuǎn)化為ValuesQuerySet
print(models.Clothes.objects.filter(color=models.Colors.objects.get(colors="紅")).values('color__colors','description')) #獲取子表的description字段,和母表的colors字段,獲取母表字段寫法: 子表外鍵字段名__母表字段名--適用于values()或filter() #簡寫形式補(bǔ)充: print(models.Clothes.objects.filter(color__colors="紅").values('color__colors','description')) #返回: [{'description': u'\u7ea2\u5185\u8863', 'color__colors': u'\u7ea2'}, {'description': u'\u7ea2\u5185\u88e4', 'color__colors': u'\u7ea2'}] #如果不加values(),返回的是[<Clothes: 大美女>, <Clothes: 小虎哥>]這樣一個QuerySet集合,通過values可以形成一個列表,列表中的每一個元素是一個字典,可以通過list()將ValuesQeurySet轉(zhuǎn)化為列表,之后返回給templates #另外可通過.values_list()將QuerySet轉(zhuǎn)化為ValuesListQuerySet。返回:[(u'\u7ea2', u'\u7ea2\u889c\u5b50'), (u'\u7ea2', u'\u7ea2\u889c\u5b50')] #得到的是一個列表,列表中是多個元組,每個元組是ValuesQuerySet中字典的value,常用于從models里將數(shù)據(jù)取出后動態(tài)添加到前端模板中的select選項(xiàng)中。 #通過forms.py從models取值傳給前端select選項(xiàng),需重啟django后,select選項(xiàng)才能更新,可在定義form時,添加如下關(guān)鍵字保障動態(tài)更新select選項(xiàng) #forms.py from django import forms from test1 import models class ClothesForm(forms.Form): color=forms.IntegerField(required=True,widget=forms.Select(),) def __init__(self,*args,**kwargs): #定義這個關(guān)鍵字段,當(dāng)使用form時,colors表新增了顏色,前端ClothesForm的color字段的選項(xiàng)會自動更新 super(ClothesForm, self).__init__(*args,**kwargs) self.fields['color'].widget.choices=models.Colors.objects.all().order_by('id').values_list('id','colors')
增:
#增添子表數(shù)據(jù),形式與一對一一致 #添加顏色為綠的服裝:小帥哥 #方法1: models.Clothes.objects.create(color=models.Colors.objects.get(colors="綠"),description="小帥哥") #方法1補(bǔ)充: models.Clothes.objects.create(color_id=models.Colors.objects.get(colors="綠").id,description="小帥哥") #方法2: c_obj=models.Clothes(color=models.Colors.objects.get(colors="綠"),description="小帥哥") c_obj.save() #方法3:字典方式錄入..參考一對一
改:
#顏色為紅的服裝,description都更新為大美女 #寫法1: models.Clothes.objects.filter(color__colors="紅").update(description="大美女") #寫法2: models.Clothes.objects.filter(color_id=models.Colors.objects.get(colors="紅").id).update(description="大美女") #寫法3: colors_obj=models.Colors.objects.get(colors="紅") colors_obj.clothes_set.filter(id__gte=1).update(description="大美女") #其他寫法參照一對一的修改和外鍵的查詢
刪:
models.Clothes.objects.get(description="灰裙子").delete() #對象和QuerySet都有方法delete() models.Colors.objects.filter(colors="灰").delete()
多對多
查:
#多對多子表查詢母表,查找小明喜歡哪些顏色--返回:[<Colors: 紅>, <Colors: 黃>, <Colors: 藍(lán)>] #與一對多子表查詢母表的形式不同,因?yàn)橐粚Χ?,查詢的是母表的“一”;多對多,查詢的是母表的“多? #寫法1: child_obj=models.Child.objects.get(name="小明") #寫法:子表對象.子表多對多字段.過濾條件(all()/filter()) print(child_obj.favor.all()) #寫法2,反向從母表入手: print(models.Colors.objects.filter(child__name="小明")) #母表對象.filter(子表表名小寫__子表字段名="過濾條件") #多對多母表查詢子表,查找有哪些人喜歡黃色--返回:[<Child: 小明>, <Child: 丫蛋>] #與一對多母表查詢子表的形式完全一致,因?yàn)椴榈降亩际荙uerySet,一對多和多對多,都是在查詢子表的“多” #寫法1: color_obj=models.Colors.objects.get(colors="黃") print(color_obj.child_set.all()) #寫法2: print(models.Child.objects.filter(favor=models.Colors.objects.get(colors="黃"))) #寫法2簡便寫法(推薦): print(models.Child.objects.filter(favor__colors="黃")) #寫法:filter(子表外鍵字段__母表字段='過濾條件') #寫法3: color_id=models.Colors.objects.get(colors="黃").id #通過母表獲取到顏色為紅的id print(models.Child.objects.filter(favor=color_id)) #filter得到QuerySet,寫法:filter(子表外鍵字段=母表主鍵對象),此處和一對多略有不同,是子表外鍵字段而不是外鍵字段_母表主鍵
增與改(增添子表或母表數(shù)據(jù)參照一對一的增,多對多重點(diǎn)在于關(guān)系表的對應(yīng)關(guān)系變更):
#添加子表關(guān)聯(lián)關(guān)系 #添加小虎并讓他喜歡所有顏色 #寫法1: child_obj=models.Child.objects.create(name="小虎") #如果是已有用戶,使用.get() colors_obj=models.Colors.objects.all() #創(chuàng)建顏色表的所有顏色QuerySet對象 child_obj.favor.add(*colors_obj) #添加對應(yīng)關(guān)系,將小虎和所有顏色進(jìn)行關(guān)聯(lián),寫法:子表對象.子表多對多字段.add(*QuerySet對象) #寫法2: child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.all() child_obj.favor=colors_obj child_obj.save() #讓小虎喜歡黃色和藍(lán)色(2種寫法和上邊一致,只展示一種寫法) child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.filter(colors__in=["藍(lán)","黃"]) #models默認(rèn)只能用這種方式得到并集,如需更復(fù)雜的過濾邏輯,需使用模塊Q child_obj.favor.clear() #清空小虎已經(jīng)喜歡的顏色 child_obj.favor.add(*colors_obj) #add是追加模式,如果當(dāng)前小虎已經(jīng)喜歡綠色,那么執(zhí)行后,小虎會額外喜歡藍(lán),黃 #讓小虎喜歡綠色(2種寫法和上邊一致,只展示一種寫法) child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.get(colors="綠") child_obj.favor.clear() child_obj.favor.add(colors_obj) #此處沒有* #添加母表關(guān)聯(lián)關(guān)系 #讓喜歡藍(lán)色的人里添加小虎,可以用上邊的方法,一個效果,讓小虎喜歡藍(lán)色,下邊介紹反向插入(從母表入手)的寫法 child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.get(colors="藍(lán)") colors_obj.child_set.add(child_obj) #從colors表插入小虎,寫法:母表對象.子表名小寫_set.add(子表對象)。 讓喜歡藍(lán)色的child_set集合添加name="小虎" #讓所有人都喜歡藍(lán)色 children_obj=models.Child.objects.all() colors_obj=models.Colors.objects.get(colors="藍(lán)") colors_obj.child_set.add(*children_obj) #關(guān)于_set寫法,是否已經(jīng)有些暈了,究竟什么時候使用_set,簡單記憶,只有子表才有"子表名小寫_set"的寫法,得到的是一個QuerySet集合,后邊可以接.add(),.remove(),.update(),.delete(),.clear() #另外備注一下,colors_obj.child_set.clear()是讓所有人喜歡的顏色里去掉藍(lán)色,colors_obj.child_set.all().delete()是刪除.child_set的所有人
刪:
刪除多對多表關(guān)系 :
#刪除子表與母表關(guān)聯(lián)關(guān)系 #讓小虎不喜歡任何顏色 #寫法1: child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.all() child_obj.favor='' child_obj.save() #寫法2: child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.all() child_obj.favor.remove(*colors_obj) #寫法3: child_obj=models.Child.objects.get(name="小虎") child_obj.favor.clear() #其他例子參照多對多的增與改案例,這里不做舉例 #刪除母表與子表關(guān)聯(lián)關(guān)系 #讓所有人不再喜歡藍(lán)色 #寫法1: children_obj=models.Child.objects.all() colors_obj=models.Colors.objects.get(colors="藍(lán)") colors_obj.child_set.remove(*children_obj) #寫法2: colors_obj=models.Colors.objects.get(colors="藍(lán)") colors_obj.child_set.clear()
刪除多對多表數(shù)據(jù):
#刪除子表數(shù)據(jù) #喜歡藍(lán)色的所有人都刪掉 colors_obj=models.Colors.objects.get(colors="藍(lán)") colors_obj.child_set.all().delete() #注意有.all() #刪除所有child models.Child.objects.all().delete()
刪除母表數(shù)據(jù):
默認(rèn)情況下,如此例中,刪除“紅”色,那么子表與顏色表是一對一或外鍵關(guān)系的,子表對應(yīng)數(shù)據(jù)會自動刪除,如:紅球,小虎哥
與顏色表是多對多關(guān)系的話,不會自動刪除喜歡紅色的人,而是去掉紅色已選
如果想讓與母表外鍵關(guān)聯(lián)的子表在刪除外鍵之后依舊可以保留子表數(shù)據(jù),需要子表建表時加入以下字段:
class Clothes(models.Model): color=models.ForeignKey("Colors",null=True,on_delete=models.SET_NULL)) #可為空,如果外鍵被刪后,子表數(shù)據(jù)此字段置空而不是直接刪除這條數(shù)據(jù),同理也可以SET_DEFAULT,需要此字段有默認(rèn)值 description=models.CharField(max_length=10) #描述
choice
#choices相當(dāng)于實(shí)現(xiàn)一個簡化版的外鍵,外鍵的選項(xiàng)不能動態(tài)更新,如可選項(xiàng)目較少,可以采用 #先在models添加choices字段 class Child(models.Model): sex_choice=((0,"男"),(1,"女")) name=models.CharField(max_length=10) #姓名 favor=models.ManyToManyField('Colors') #與顏色表為多對多 sex=models.IntegerField(choices=sex_choice,default=0) def __unicode__(self): return self.name #在views.py中調(diào)用 child_obj=models.Child.objects.get(name="小虎") print(child_obj.sex) #返回0或1 print(child_obj.get_sex_display()) #返回男或女
以上這篇基于Django ORM、一對一、一對多、多對多的全面講解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
- django框架使用orm實(shí)現(xiàn)批量更新數(shù)據(jù)的方法
- Django使用詳解:ORM 的反向查找(related_name)
- Django ORM 查詢表中某列字段值的方法
- Django基于ORM操作數(shù)據(jù)庫的方法詳解
- Django ORM 聚合查詢和分組查詢實(shí)現(xiàn)詳解
- Django ORM框架的定時任務(wù)如何使用詳解
- Django中ORM表的創(chuàng)建和增刪改查方法示例
- django的ORM模型的實(shí)現(xiàn)原理
- django 常用orm操作詳解
- 淺談django orm 優(yōu)化
- Django中ORM的基本使用教程
相關(guān)文章
Python Lambda函數(shù)使用總結(jié)詳解
這篇文章主要介紹了Python Lambda函數(shù)使用總結(jié)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12python如何使用pywebview打造一個現(xiàn)代化的可視化GUI界面詳解
pywebview是一個輕量級的跨平臺庫,它可以讓你在Python程序中嵌入一個瀏覽器窗口,下面這篇文章主要給大家介紹了關(guān)于python如何使用pywebview打造一個現(xiàn)代化的可視化GUI界面的相關(guān)資料,需要的朋友可以參考下2024-07-07Python+OpenCV 圖像邊緣檢測四種實(shí)現(xiàn)方法
本文主要介紹了通過OpenCV中Sobel算子、Schaar算子、Laplacian算子以及Canny分別實(shí)現(xiàn)圖像邊緣檢測并總結(jié)了四者的優(yōu)缺點(diǎn),感興趣的同學(xué)可以參考一下2021-11-11es+flask搜索小項(xiàng)目實(shí)現(xiàn)分頁+高亮的示例代碼
本文主要介紹了es+flask搜索小項(xiàng)目實(shí)現(xiàn)分頁+高亮的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01python實(shí)現(xiàn)AES算法及AES-CFB8加解密源碼
這篇文章主要為大家介紹了python實(shí)現(xiàn)AES算法及AES-CFB8加解密的源碼示例,有需要朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02python爬不同圖片分別保存在不同文件夾中的實(shí)現(xiàn)
這篇文章主要介紹了python爬不同圖片分別保存在不同文件夾中的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04PyTorch實(shí)現(xiàn)重寫/改寫Dataset并載入Dataloader
這篇文章主要介紹了PyTorch實(shí)現(xiàn)重寫/改寫Dataset并載入Dataloader,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07