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 字段,自己链表查询
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) # 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)两条关系 # 2、删除 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)条目 # 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增删改查
一大波Model操作
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') 基本操作
Model性能相关操作:select_related、prefetch_related
1、普通查询的缺点
1. 例:现在有两张表user,和group两张表,在user表中使用m作为ForeignKey与group表进行一对多关联
2. 如果通过user表中的实例查找对应的group表中的数据,就必须重复发sql请求
3. prefetch_related()和select_related()的设计目,都是为了减少SQL查询的数量,但是实现的方式不一样
2、select_related作用
1. select_related主要针一对一和多对一关系进行优化。
2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
3、prefetch_related()作用
1. prefetch_related()主要对于多对多字段和一对多字段进行优化
2. 进行两次sql查询,将查询结果拼接成一张表放到内存中,再查询就不用发sql请求
4、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举例说明