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