Django ORM、一對1、一對多、多對多、詳解

 

上篇博客也提到這些知識點,可能你們仍是不太清楚,這篇博客爲你們詳細講解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')    #與顏色表爲多對多

 

先來區分一下什麼是一對1、多對多


  一對一:子表從母表中選出一條數據一一對應,母表中選出來一條就少一條,子表不能夠再選擇母表中已被選擇的那條數據python

  一對多:子表從母表中選出一條數據一一對應,但母表的這條數據還能夠被其餘子表數據選擇django

共同點是在admin中添加數據的話,都會出現一個select選框,但只能單選,由於不論一對一仍是一對多,本身都是「一」服務器

多對多總結:ui

  好比有多個孩子,和多種顏色、spa

  每一個孩子能夠喜歡多種顏色,一種顏色能夠被多個孩子喜歡,對於雙向均是能夠有多個選擇code

應用場景

一對一:通常用於某張表的補充,好比用戶基本信息是一張表,但並不是每個用戶都須要有登陸的權限,不須要記錄用戶名和密碼,此時,合理的作法就是新建一張記錄登陸信息的表,與用戶信息進行一對一的關聯,能夠方便的從子表查詢母表信息或反向查詢orm

外鍵:有不少的應用場景,好比每一個員工歸屬於一個部門,那麼就可讓員工表的部門字段與部門表進行一對多關聯,能夠查詢到一個員工歸屬於哪一個部門,也可反向查出某一部門有哪些員工對象

多對多:如不少公司,一臺服務器可能會有多種用途,歸屬於多個產品線當中,那麼服務器與產品線之間就能夠作成對多對,多對多在A表添加manytomany字段或者從B表添加,效果一致blog

 

一對一

查:

#子表查詢母表,找到紅球對應的顏色
#寫法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())  #返回男或女

 

都2點了,差很少也寫完了,寫註釋寫的手都疼、有什麼不清楚的能夠在下面評論,看見會盡快作回覆!!

相關文章
相關標籤/搜索