您好,登錄后才能下訂單哦!
這篇文章主要介紹了基于Django中ORM、一對一、一對多、多對多的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
1.1首先我們先看一個小案例:
#_*_coding:utf-8_*_ from django.db import models # Create your models here. class Colors(models.Model): colors=models.CharField(max_length=10) #藍色 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') #與顏色表為多對多
先來區分一下什么是一對一、多對多
一對一:子表從母表中選出一條數據一一對應,母表中選出來一條就少一條,子表不可以再選擇母表中已被選擇的那條數據
一對多:子表從母表中選出一條數據一一對應,但母表的這條數據還可以被其他子表數據選擇
共同點是在admin中添加數據的話,都會出現一個select選框,但只能單選,因為不論一對一還是一對多,自己都是“一”
多對多總結:
比如有多個孩子,和多種顏色、
每個孩子可以喜歡多種顏色,一種顏色可以被多個孩子喜歡,對于雙向均是可以有多個選擇
應用場景
一對一:一般用于某張表的補充,比如用戶基本信息是一張表,但并非每一個用戶都需要有登錄的權限,不需要記錄用戶名和密碼,此時,合理的做法就是新建一張記錄登錄信息的表,與用戶信息進行一對一的關聯,可以方便的從子表查詢母表信息或反向查詢
外鍵:有很多的應用場景,比如每個員工歸屬于一個部門,那么就可以讓員工表的部門字段與部門表進行一對多關聯,可以查詢到一個員工歸屬于哪個部門,也可反向查出某一部門有哪些員工
多對多:如很多公司,一臺服務器可能會有多種用途,歸屬于多個產品線當中,那么服務器與產品線之間就可以做成對多對,多對多在A表添加manytomany字段或者從B表添加,效果一致
一對一
查:
#子表查詢母表,找到紅球對應的顏色 #寫法1: print(models.Ball.objects.get(description="紅球").color.colors) #返回紅,通過子表查詢母表,寫法:"子表對象.母表表名的小寫.母表字段名" ;通過Ball表查到description為"紅球",查找到對應colors #寫法2,反向從母表入手: print(models.Colors.objects.get(ball__description="紅球").colors) #返回紅,通過子表查詢母表,但形式上是從母表對象自身直接獲取字段,寫法:"母表.objects.get(子表名小寫__子表字段="xxx").母表字段名" ;效果和上邊完全一致,另一種形式 #母表查詢子表,找到紅色對應的球的名字 #寫法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="黑") #先在母表中創建顏色,并實例化給顏色表對象 models.Ball.objects.create(color=color_obj,description="黑球") #更新Ball表,color字段為顏色表對象,添加description字段
備注:增添數據的3種常用方式
#增添數據的三種寫法: #寫法1: color_obj=models.Colors.objects.create(colors="黑") models.Ball.objects.create(color=color_obj,description="黑球") #寫法1補充: 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(字典導入): 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的方法
備注:修改數據的常見方式
#更新一條數據 color_obj=models.Colors.objects.get(colors="黑") color_obj.colors="灰" color_obj.save() #更新多條數據,把滿足條件的球的description都變為灰球 #寫法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() #清空一張表
一對多(外鍵)
查:
#外鍵表聯合查詢: #外鍵子表查詢母表,與一對一子表查詢母表形式一致 #找到紅褲衩所屬的顏色表中的顏色--返回:紅 #寫法1: print(models.Clothes.objects.get(description="小虎哥").color.colors) #返回紅,通過子表查詢母表,寫法:"子表對象.母表表名的小寫.母表字段名" ;通過Clothes表查到description為"小虎哥",查找到對應colors #寫法2,反向從母表入手: print(models.Colors.objects.get(clothes__description="小虎哥").colors) #返回紅,通過子表查詢母表,但形式上是從母表對象自身直接獲取字段,寫法:"母表.objects.get(子表名小寫__子表字段="xxx").母表字段名" ;效果和上邊完全一致,另一種形式 #外鍵母表查詢子表,與一對一形式不同,因為母表為"多",不能像一對一一樣通過.get().子表.子表字段的方式獲取,但與多對多母表查詢子表一致 #找到顏色為紅的所有服裝--返回:[<Clothes: 大美女>, <Clothes: 小虎哥>] #寫法1: color_obj=models.Colors.objects.get(colors="紅") print(color_obj.clothes_set.all()) #注意:子表小寫_set的寫法,它實際上是一個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轉化為ValuesQuerySet
print(models.Clothes.objects.filter(color=models.Colors.objects.get(colors="紅")).values('color__colors','description')) #獲取子表的description字段,和母表的colors字段,獲取母表字段寫法: 子表外鍵字段名__母表字段名--適用于values()或filter() #簡寫形式補充: 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轉化為列表,之后返回給templates #另外可通過.values_list()將QuerySet轉化為ValuesListQuerySet。返回:[(u'\u7ea2', u'\u7ea2\u889c\u5b50'), (u'\u7ea2', u'\u7ea2\u889c\u5b50')] #得到的是一個列表,列表中是多個元組,每個元組是ValuesQuerySet中字典的value,常用于從models里將數據取出后動態添加到前端模板中的select選項中。 #通過forms.py從models取值傳給前端select選項,需重啟django后,select選項才能更新,可在定義form時,添加如下關鍵字保障動態更新select選項 #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): #定義這個關鍵字段,當使用form時,colors表新增了顏色,前端ClothesForm的color字段的選項會自動更新 super(ClothesForm, self).__init__(*args,**kwargs) self.fields['color'].widget.choices=models.Colors.objects.all().order_by('id').values_list('id','colors')
增:
#增添子表數據,形式與一對一一致 #添加顏色為綠的服裝:小帥哥 #方法1: models.Clothes.objects.create(color=models.Colors.objects.get(colors="綠"),description="小帥哥") #方法1補充: 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: 藍>] #與一對多子表查詢母表的形式不同,因為一對多,查詢的是母表的“一”;多對多,查詢的是母表的“多” #寫法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: 丫蛋>] #與一對多母表查詢子表的形式完全一致,因為查到的都是QuerySet,一對多和多對多,都是在查詢子表的“多” #寫法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(子表外鍵字段=母表主鍵對象),此處和一對多略有不同,是子表外鍵字段而不是外鍵字段_母表主鍵
增與改(增添子表或母表數據參照一對一的增,多對多重點在于關系表的對應關系變更):
#添加子表關聯關系 #添加小虎并讓他喜歡所有顏色 #寫法1: child_obj=models.Child.objects.create(name="小虎") #如果是已有用戶,使用.get() colors_obj=models.Colors.objects.all() #創建顏色表的所有顏色QuerySet對象 child_obj.favor.add(*colors_obj) #添加對應關系,將小虎和所有顏色進行關聯,寫法:子表對象.子表多對多字段.add(*QuerySet對象) #寫法2: child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.all() child_obj.favor=colors_obj child_obj.save() #讓小虎喜歡黃色和藍色(2種寫法和上邊一致,只展示一種寫法) child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.filter(colors__in=["藍","黃"]) #models默認只能用這種方式得到并集,如需更復雜的過濾邏輯,需使用模塊Q child_obj.favor.clear() #清空小虎已經喜歡的顏色 child_obj.favor.add(*colors_obj) #add是追加模式,如果當前小虎已經喜歡綠色,那么執行后,小虎會額外喜歡藍,黃 #讓小虎喜歡綠色(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) #此處沒有* #添加母表關聯關系 #讓喜歡藍色的人里添加小虎,可以用上邊的方法,一個效果,讓小虎喜歡藍色,下邊介紹反向插入(從母表入手)的寫法 child_obj=models.Child.objects.get(name="小虎") colors_obj=models.Colors.objects.get(colors="藍") colors_obj.child_set.add(child_obj) #從colors表插入小虎,寫法:母表對象.子表名小寫_set.add(子表對象)。 讓喜歡藍色的child_set集合添加name="小虎" #讓所有人都喜歡藍色 children_obj=models.Child.objects.all() colors_obj=models.Colors.objects.get(colors="藍") colors_obj.child_set.add(*children_obj) #關于_set寫法,是否已經有些暈了,究竟什么時候使用_set,簡單記憶,只有子表才有"子表名小寫_set"的寫法,得到的是一個QuerySet集合,后邊可以接.add(),.remove(),.update(),.delete(),.clear() #另外備注一下,colors_obj.child_set.clear()是讓所有人喜歡的顏色里去掉藍色,colors_obj.child_set.all().delete()是刪除.child_set的所有人
刪:
刪除多對多表關系 :
#刪除子表與母表關聯關系 #讓小虎不喜歡任何顏色 #寫法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() #其他例子參照多對多的增與改案例,這里不做舉例 #刪除母表與子表關聯關系 #讓所有人不再喜歡藍色 #寫法1: children_obj=models.Child.objects.all() colors_obj=models.Colors.objects.get(colors="藍") colors_obj.child_set.remove(*children_obj) #寫法2: colors_obj=models.Colors.objects.get(colors="藍") colors_obj.child_set.clear()
刪除多對多表數據:
#刪除子表數據 #喜歡藍色的所有人都刪掉 colors_obj=models.Colors.objects.get(colors="藍") colors_obj.child_set.all().delete() #注意有.all() #刪除所有child models.Child.objects.all().delete()
刪除母表數據:
默認情況下,如此例中,刪除“紅”色,那么子表與顏色表是一對一或外鍵關系的,子表對應數據會自動刪除,如:紅球,小虎哥
與顏色表是多對多關系的話,不會自動刪除喜歡紅色的人,而是去掉紅色已選
如果想讓與母表外鍵關聯的子表在刪除外鍵之后依舊可以保留子表數據,需要子表建表時加入以下字段:
class Clothes(models.Model): color=models.ForeignKey("Colors",null=True,on_delete=models.SET_NULL)) #可為空,如果外鍵被刪后,子表數據此字段置空而不是直接刪除這條數據,同理也可以SET_DEFAULT,需要此字段有默認值 description=models.CharField(max_length=10) #描述
choice
#choices相當于實現一個簡化版的外鍵,外鍵的選項不能動態更新,如可選項目較少,可以采用 #先在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中調用 child_obj=models.Child.objects.get(name="小虎") print(child_obj.sex) #返回0或1 print(child_obj.get_sex_display()) #返回男或女
感謝你能夠認真閱讀完這篇文章,希望小編分享的“基于Django中ORM、一對一、一對多、多對多的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。