from django.db import models class UserInfo(models.Model): username = models.CharField(max_length=32) def __str__(self): return self.username class UserGroup(models.Model): group_name = models.CharField(max_length=64) user_info = models.ManyToManyField(to='UserInfo',related_query_name='m2m') def __str__(self): return self.group_name 第一種:models.py 建立多對多表
from django.shortcuts import HttpResponse from app01 import models def orm(request): user_info_obj = models.UserInfo.objects.get(username='zhangsan') user_info_objs = models.UserInfo.objects.all() group_obj = models.UserGroup.objects.get(group_name='group_python') group_objs = models.UserGroup.objects.all() # 添加: 正向 group_obj.user_info.add(user_info_obj) group_obj.user_info.add(*user_info_objs) # 刪除:正向 group_obj.user_info.remove(user_info_obj) group_obj.user_info.remove(*user_info_objs) # 添加: 反向 user_info_obj.usergroup_set.add(group_obj) user_info_obj.usergroup_set.add(*group_objs) # 刪除:反向 user_info_obj.usergroup_set.remove(group_obj) user_info_obj.usergroup_set.remove(*group_objs) # 查找:正向 print(group_obj.user_info.all()) # 查找group_python組中全部用戶 print(group_obj.user_info.all().filter(username='zhangsan')) # 查找:反向 print(user_info_obj.usergroup_set.all()) # 查找用戶zhangsan屬於那些組 print(user_info_obj.usergroup_set.all().filter(group_name='group_python')) # 雙下劃線 正向、反向查找 # 正向:從用戶組表中查找zhangsan屬於哪一個用戶組:[<UserGroup: group_python>] print( models.UserGroup.objects.filter(user_info__username='zhangsan')) # 反向:從用戶表中查詢group_python組中有哪些用戶:related_query_name='m2m' print( models.UserInfo.objects.filter(m2m__group_name='group_python')) # 自動建立UserInfo表和UserGroup表中的數據 ''' user_list = [{'username':'zhangsan'}, {'username':'lisi'}, {'username':'wangwu'},] group_list = [{'group_name':'group_python'}, {'group_name':'group_linux'}, {'group_name':'group_mysql'},] for c in user_list: models.UserInfo.objects.create(**c) for l in group_list: models.UserGroup.objects.create(**l) ''' return HttpResponse('orm') 第一種:views.py 根據queryset對象增刪改查
第二種: 本身建立第三張關係表,無 m2m 字段,本身鏈表查詢html
from django.db import models #表1:主機表 class Host(models.Model): nid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32,db_index=True) #表2:應用表 class Application(models.Model): name = models.CharField(max_length=32) #表3:自定義第三張關聯表 class HostToApp(models.Model): hobj = models.ForeignKey(to="Host",to_field="nid") aobj = models.ForeignKey(to='Application',to_field='id') # 向第三張表插入數據,創建多對多外鍵關聯 HostToApp.objects.create(hobj_id=1,aobj_id=2) 第二種: 有第三張表,無m2m字段 models.py
from django.db import models class Host(models.Model): hostname = models.CharField(max_length=32,db_index=True) class Group(models.Model): group_name = models.CharField(max_length=32) m2m = models.ManyToManyField("Host") 第三種: models.py建立多對多表
from django.shortcuts import HttpResponse from app01 import models def orm(request): # 使用間接方法對第三張表操做 obj = models.Group.objects.get(id=1) # 一、添加 obj.m2m.add(1) # 在第三張表中增長一個條目(1,1) obj.m2m.add(2, 3) # 在第三張表中增長條目(1,2)(1,3)兩條關係 obj.m2m.add(*[1,3]) # 在第三張表中增長條目(1,2)(1,3)兩條關係 # 二、刪除 obj.m2m.remove(1) # 刪除第三張表中的(1,1)條目 obj.m2m.remove(2, 3) # 刪除第三張表中的(1,2)(1,3)條目 obj.m2m.remove(*[1, 2, 3]) # 刪除第三張表中的(1,1)(1,2)(1,3)條目 # 三、清空 obj.m2m.clear() # 刪除第三張表中application條目等於1的全部條目 # 4 更新 obj.m2m.set([1, 2,]) # 第三張表中會刪除全部條目,而後建立(1,1)(1,2)條目 # 5 查找 print( obj.m2m.all() ) # 等價於 models.UserInfo.objects.all() # 6 反向查找: 雙下劃線 hosts = models.Group.objects.filter(m2m__id=1) # 在Host表中id=1的主機同時屬於那些組 # 自動建立Host表和Group表中的數據 ''' hostname = [{'hostname':'zhangsan'}, {'hostname':'lisi'}, {'hostname':'wangwu'},] group_name = [{'group_name':'DBA'},{'group_name':'public'},] for h in hostname: models.Host.objects.create(**h) for u in group_name: models.Group.objects.create(**u) ''' return HttpResponse('orm') 第三種:views.py 根據id增刪改查
from django.shortcuts import HttpResponse from app01 import models def orm(request): # 1 建立 # 建立數據方法一 models.UserInfo.objects.create(username='root', password='123') # 建立數據方法二 obj = models.UserInfo(username='alex', password='123') obj.save() # 建立數據庫方法三(傳入字典必須在字典前加兩個星號) dic = {'username': 'eric', 'password': '666'} models.UserInfo.objects.create(**dic) # 2 查 result = models.UserInfo.objects.all() # 查找全部條目 result = models.UserInfo.objects.filter(username='alex', password='123') for row in result: print(row.id, row.username, row.password) # 3 刪除 models.UserInfo.objects.all().delete() # 刪除全部 models.UserInfo.objects.filter(username='alex').delete() # 刪除指定 # 4 更新 models.UserInfo.objects.all().update(password='12345') models.UserInfo.objects.filter(id=4).update(password='15') # 5 獲取個數 models.UserInfo.objects.filter(name='seven').count() # 6 執行原生SQL # 6.1 執行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 6.2 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名 models.UserInfo.objects.raw('select id as nid from 其餘表') # 6.3 指定數據庫 models.UserInfo.objects.raw('select * from userinfo', using="default") return HttpResponse('orm') 基本操做
一、普通查詢的缺點python
1. 例:如今有兩張表user,和group兩張表,在user表中使用m做爲ForeignKey與group表進行一對多關聯mysql
2. 若是經過user表中的實例查找對應的group表中的數據,就必須重複發sql請求linux
3. prefetch_related()和select_related()的設計目,都是爲了減小SQL查詢的數量,可是實現的方式不同 sql
二、select_related做用數據庫
1. select_related主要針一對一和多對一關係進行優化。django
2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。app
三、prefetch_related()做用性能
1. prefetch_related()主要對於多對多字段和一對多字段進行優化fetch
2. 進行兩次sql查詢,將查詢結果拼接成一張表放到內存中,再查詢就不用發sql請求
四、select_related與prefetch_related 使用原則
1. prefetch_related()和select_related()的設計目的很類似,都是爲了減小SQL查詢的數量,可是實現的方式不同
2. 由於select_related()老是在單次SQL查詢中解決問題,而prefetch_related()會對每一個相關表進行SQL查詢,所以select_related()的效率高
3. 因此儘量的用select_related()解決問題。只有在select_related()不能解決問題的時候再去想prefetch_related()。
def index(request): users = models.User.objects.filter(id__gt=30).prefetch_related('ut') #ut和tu是user表的兩個foreign key,分別關聯不一樣的表 users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu') #1 先執行第一次sql查詢:select * from users where id > 30; #2 好比:第一次查詢結果,獲取上一步驟中全部ut_id=[1,2] #3 而後執行第二次sql查詢:select * from user_type where id in [1,2] #4 這樣就僅執行了兩次sql查詢將兩個表的數據拼到一塊兒,放到內存中,再查詢就不用發sql請求 for row in users: print(row.user,row.ut_id) #這裏打印user表中的內容沒必要再次sql請求 prefetch_related舉例說明
def index(request): #1 這種方法低效 users = models.User.objects.all() #拿到的僅僅是user表中內容 for row in users: print(row.user,row.ut_id) #這裏打印user表中的內容沒必要再次sql請求 print(row.ut.name) #第一次查表,沒有拿到關聯表ut字段中的內容 #因此每次循環都會再次發sql請求,拿到ut.name的值,低效 #2 使用這種方法也僅須要一次數據庫查詢(拿到的是字典),可是若是查找的不在那些字段中直接報錯 users = models.User.objects.all().values('user','pwd','ut__name') #3 select_related()能夠一次sql查詢拿到全部關聯表信息 users = models.User.objects.all().select_related() # 這裏還支持指定只拿到那個關聯表的全部信息,好比:有多個外鍵關聯,只拿到與ut外鍵關聯的表 users = models.User.objects.all().select_related('ut') # select_related() 接受depth參數,depth參數能夠肯定select_related的深度。 # Django會遞歸遍歷指定深度內的全部的OneToOneField和ForeignKey。以本例說明: # zhangs = Person.objects.select_related(depth = d) # d=1 至關於 select_related(‘hometown’,'living’) # d=2 至關於 select_related(‘hometown__province’,'living__province’) select_related舉例說明