一. 多對多表ManyToManyField (ORM)
https://www.cnblogs.com/yoyoketang/p/10580253.html 多對多(ManyToManyField)查詢
https://www.cnblogs.com/yuanchenqi/articles/8963244.html 多表操作
1.創建orm表
多對多手動創建第三張關系表聯
# 表一 class User(models.Model): username=models.CharField(max_length=24,db_index=True) def __str__(self): return self.username # 表二 class Tag(models.Model): title=models.CharField(max_length=24) def __str__(self): return self.title # 自定義第三張表 class UserToTag(models.Model): u=models.ForeignKey(to="User") t=models.ForeignKey(to="Tag") ctime=models.DateField()
多對多手動創建第三張關系表聯合唯一
# 表一 class User(models.Model): username=models.CharField(max_length=24,db_index=True) def __str__(self): return self.username # 表二 class Tag(models.Model): title=models.CharField(max_length=24) def __str__(self): return self.title # m=models.ManyToManyField( # ManyToManyField d多對多 使用 ManyToManyField 只能在第三章表 中創建三列數 # to="User" , # 默認和user表的主鍵進行管理 # ) # 自定義第三張表 class UserToTag(models.Model): u=models.ForeignKey(to="User") t=models.ForeignKey(to="Tag") ctime=models.DateField() class Meta: # 表示聯合唯一 和 ManyToManyField 差不多 unique_together=[ # 表達的意思就是標簽和同一個人不能出現多次 就一個人對應一個標簽 ("u","t"), ]
ManyToManyField自動創建第三表
class Colors(models.Model): colors=models.CharField(max_length=10) #藍色 def __str__(self): return self.colors class Child(models.Model): name=models.CharField(max_length=10) #姓名 favor=models.ManyToManyField('Colors') #與顏色表為多對多
比如有多個孩子,和多種顏色、
每個孩子可以喜歡多種顏色,一種顏色可以被多個孩子喜歡,對於雙向均是可以有多個選擇
查數據
#多對多子表查詢母表,查找小明喜歡哪些顏色--返回:[<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
# models.py form django.db import models class Book(models.Model): # 表名book,django會自動使用項目名+我們定義的表名 # 如沒有自定義主鍵,django會自動添加一個主鍵,字段名id 自增 name = models.CharField(max_length=20) # 字段名name 類型 vachar(20) price = models.IntegerField() # 字段名price 類型int pub_date = models.DateField() # 字段名pub_date 類型 date (時間戳) publish = models.ForeighKey('Publish') # 創建外鍵關聯到Publish表的id字段,django會自動將該名稱改為publish_id # 如果這樣寫 publish = models.ForeighKey(Publish) 括號內無引號,則必須將Publish類放到Book類的上面 authors = models.ManyToManyField('Author',related_name='xxx') 將book與author表做多對多關系 related_name 同一對多中的說明 # django會自動創建一張表(book與author的中間關聯表)名稱為appname_book_authors def __str__(self): return self.name # 打印實例對象時顯示為self.name #class Book_Author(models.Model): 自己創建第三張表 # book = models.ForeignKey('book') # author = models.ForeignKey('Author') class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name
多對多的添加設置刪除
# views.py from django.shortcuts import render from app_name.models import * # 導入models.py def add(request): # 增加數據的視圖函數 # 系統自己創建的第三張表使用創建對象操作 book_obj = Book.objects.get(id=4) # 取出id為4的書 # book_obj.authors.all() 此時取出的是一個空的集合 authors_obj = Author.objects.all() # 取出所有author名稱的集合 book_obj.authors.add(*author_obj) # 將所有作者添加到這本書中 book_obj.authors.remove(*author_obj) # 將所有作者從書中刪除 book_obj.authors.add(2) # 將id為2的作者添加到此書 book.obj.authors.add([1,2]) # 將id為1和2的作者添加到此書 book_obj.authors.remove(1) # 將id為1的作者從書中刪除 book_obj.authors.clear() # 清除此書所有的作者 book_obj.authors.set([2,3,4]) # 將書的作者設置為id為2,3,4的作者 (相當於重新設置) # 我們自己定義的第三張表(不常用) Book_Author.objects.create(book_id=2, author_id=3) obj = Book.objects.get(id=2) obj.book_author_set.all()[0]l.author return HttpResponse('xxx')
多對多的查詢
# 怎么使用多對多查詢呢? book_obj = Book.objects.get(name='python') print(book_obj.name) # python print(book_obj.authors.all()) # QuerySet 返回一個QuerySet對象,里面是author的實例集合 print(type(book_obj.authors.all())) # <class 'django.db.models.query.QuerySet'> 1、查詢作者id為2出的所有的書 author_obj=Author.objects.get(id=2) author_obj.book_set.all() 2、查詢三班所對應的所有老師 obj = Classes.objects.filter(name='三班').first() 從班級表取出三班 obj.m.all() # 從三班中取所有的老師 m表示多對多關系的名稱 還是通過雙下划線 2、查詢作者alex出的所有書 Book.objects.filter(authors__name='alex').values('name','price')