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') #與顏色表為多對多
先來區(qū)分一下什么是一對一跺涤、多對多
一對一:子表從母表中選出一條數(shù)據(jù)一一對應(yīng)匈睁,母表中選出來一條就少一條管钳,子表不可以再選擇母表中已被選擇的那條數(shù)據(jù)
一對多:子表從母表中選出一條數(shù)據(jù)一一對應(yīng),但母表的這條數(shù)據(jù)還可以被其他子表數(shù)據(jù)選擇
共同點是在admin中添加數(shù)據(jù)的話软舌,都會出現(xiàn)一個select選框,但只能單選牛曹,因為不論一對一還是一對多佛点,自己都是“一”
多對多總結(jié):
比如有多個孩子,和多種顏色黎比、
每個孩子可以喜歡多種顏色超营,一種顏色可以被多個孩子喜歡,對于雙向均是可以有多個選擇
應(yīng)用場景
一對一:一般用于某張表的補充阅虫,比如用戶基本信息是一張表演闭,但并非每一個用戶都需要有登錄的權(quán)限,不需要記錄用戶名和密碼颓帝,此時米碰,合理的做法就是新建一張記錄登錄信息的表,與用戶信息進行一對一的關(guān)聯(lián)购城,可以方便的從子表查詢母表信息或反向查詢
外鍵:有很多的應(yīng)用場景吕座,比如每個員工歸屬于一個部門,那么就可以讓員工表的部門字段與部門表進行一對多關(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)建顏色烧栋,并實例化給顏色表對象
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補充:
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").母表字段名" 轴踱;效果和上邊完全一致症脂,另一種形式
#外鍵母表查詢子表,與一對一形式不同,因為母表為"多"淫僻,不能像一對一一樣通過.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轉(zhuǎn)化為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轉(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選項中桦他。
#通過forms.py從models取值傳給前端select選項,需重啟django后谆棱,select選項才能更新快压,可在定義form時圆仔,添加如下關(guān)鍵字保障動態(tài)更新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): #定義這個關(guān)鍵字段,當(dāng)使用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')
增:
#增添子表數(shù)據(jù),形式與一對一一致
#添加顏色為綠的服裝:小帥哥
#方法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(子表外鍵字段=母表主鍵對象),此處和一對多略有不同外驱,是子表外鍵字段而不是外鍵字段_母表主鍵
增與改(增添子表或母表數(shù)據(jù)參照一對一的增,多對多重點在于關(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)系,將小虎和所有顏色進行關(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()
#讓小虎喜歡黃色和藍色(2種寫法和上邊一致,只展示一種寫法)
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.filter(colors__in=["藍","黃"]) #models默認(rèn)只能用這種方式得到并集儿子,如需更復(fù)雜的過濾邏輯瓦哎,需使用模塊Q
child_obj.favor.clear() #清空小虎已經(jīng)喜歡的顏色
child_obj.favor.add(*colors_obj) #add是追加模式,如果當(dāng)前小虎已經(jīng)喜歡綠色柔逼,那么執(zhí)行后蒋譬,小虎會額外喜歡藍,黃
#讓小虎喜歡綠色(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)系
#讓喜歡藍色的人里添加小虎,可以用上邊的方法犯助,一個效果,讓小虎喜歡藍色维咸,下邊介紹反向插入(從母表入手)的寫法
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)
#關(guān)于_set寫法癌蓖,是否已經(jīng)有些暈了瞬哼,究竟什么時候使用_set,簡單記憶,只有子表才有"子表名小寫_set"的寫法费坊,得到的是一個QuerySet集合倒槐,后邊可以接.add(),.remove(),.update(),.delete(),.clear()
#另外備注一下,colors_obj.child_set.clear()是讓所有人喜歡的顏色里去掉藍色附井,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)系
#讓所有人不再喜歡藍色
#寫法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()
刪除多對多表數(shù)據(jù):
#刪除子表數(shù)據(jù)
#喜歡藍色的所有人都刪掉
colors_obj=models.Colors.objects.get(colors="藍")
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)于實現(xiàn)一個簡化版的外鍵慈迈,外鍵的選項不能動態(tài)更新,如可選項目較少省有,可以采用
#先在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)容了伸头,希望能給大家一個參考,也希望大家多多支持腳本之家舷蟀。