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举例说明