基础操作:
- 创建:
# 创建数据方法一
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)
- 查找:
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)
- 删除:
models.UserInfo.objects.all().delete() # 删除所有
models.UserInfo.objects.filter(username='alex').delete() # 删除指定
- 跟新:
models.UserInfo.objects.all().update(password='12345')
models.UserInfo.objects.filter(id=4).update(password='15')
- 获取个数:
models.UserInfo.objects.filter(name='seven').count()
- 执行原生SQL语句:
- 执行原生SQL
models.UserInfo.objects.raw('select * from userinfo')
- 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
models.UserInfo.objects.raw('select id as nid from 其他表')
- 指定数据库
models.UserInfo.objects.raw('select * from userinfo', using="default")
- 执行原生SQL
进阶操作(双下划线)
- 大于,小于
models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
- in
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
- isnull
Entry.objects.filter(pub_date__isnull=True) #双下划线isnull,查找pub_date是null的数据
- contains
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
models.Tb1.objects.exclude(name__icontains="ven")
- range
models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
- order by
models.Tb1.objects.filter(name='seven').order_by('id') # asc 没有减号升续排列
models.Tb1.objects.filter(name='seven').order_by('-id') # desc 有减号升续排列
- group by
from django.db.models import Count, Min, Max, Sum
models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) #根据id列进行分组
SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1"
WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
- limit、offset
models.Tb1.objects.all()[10:20]
- regex正则匹配(不区别大小写)
在这里插入代码片
- date
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) #__data表示日期查找,2005-01-01
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
- year
Entry.objects.filter(pub_date__year=2005) #__year根据年查找
Entry.objects.filter(pub_date__year__gte=2005)
- month
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
- day
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
- week_day
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
- hour
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)
- minute
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)
- second
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)
Model性能相关操作:select_related、prefetch_related
-
普通查询的缺点
-
例:现在有两张表user,和group两张表,在user表中使用m作为ForeignKey与group表进行一对多关联
-
如果通过user表中的实例查找对应的group表中的数据,就必须重复发sql请求
-
prefetch_related()和select_related()的设计目,都是为了减少SQL查询的数量,但是实现的方式不一样
-
-
select_related作用
-
select_related主要针一对一和多对一关系进行优化。
-
select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
-
-
prefetch_related()作用
-
prefetch_related()主要对于多对多字段和一对多字段进行优化
-
进行两次sql查询,将查询结果拼接成一张表放到内存中,再查询就不用发sql请求
-
-
select_related与prefetch_related 使用原则
-
prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询的数量,但是实现的方式不一样
-
因为select_related()总是在单次SQL查询中解决问题,而prefetch_related()会对每个相关表进行SQL查询,因此select_related()的效率高
-
所以尽可能的用select_related()解决问题。只有在select_related()不能解决问题的时候再去想prefetch_related()。
-
-
select_related举例说明
作用:使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化
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’)
- prefetch_related举例说明
作用:进行两次sql查询,将查询结果拼接成一张表
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请求
F()和Q()查询语句
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
def __str__(self):
return self.name
- F() ---- 专门取对象中某列值的操作
作用:F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用
from django.shortcuts import HttpResponse
from app01 import models
from django.db.models import F,Q
def orm(request):
# 每访问一次数据库中zhangsan的年纪就会自动增加1
models.Student.objects.filter(name='zhangsan').update(age=F("age") + 1)
# 自动生成Student表中数据
'''
stu_list = [{'name':'zhangsan','age':11},
{'name': 'lisi', 'age': 22},
{'name': 'wangwu', 'age': 33},]
for u in stu_list:
models.Student.objects.create(**u)
'''
return HttpResponse('orm')
- Q() ---- 复杂查询(用法1)
-
Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
-
可以组合使用 &(and),|(or),~(not)操作符,当一个操作符用于两个Q的对象,它产生一个新的Q对象
-
如: Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=‘root’)
from django.shortcuts import HttpResponse
from app01 import models
from django.db.models import F,Q
def orm(request):
# 查找学生表中年级大于1小于30姓zhang的所有学生
stus = models.Student.objects.filter(
Q(age__gt=1) & Q(age__lt=30),
Q(name__startswith='zhang')
)
print('stu',stus) #运行结果:[<Student: zhangsan>]
# 自动生成Student表中数据
'''
stu_list = [{'name':'zhangsan','age':11},
{'name': 'lisi', 'age': 22},
{'name': 'wangwu', 'age': 33},]
for u in stu_list:
models.Student.objects.create(**u)
'''
return HttpResponse('orm')
- Q() ---- 动态添加多个and和or查询条件(用法2)
# crm项目中动态添加or查询条件
def table_search(request,admin_class,object_list):
search_key = request.GET.get('_q','')
q_obj = Q()
q_obj.connector = 'OR'
for column in admin_class.search_fields:
q_obj.children.append(('%s__contains'%column,search_key))
res = object_list.filter(q_obj)
return res
# or动态添加多个查询条件
>>> from crm import models
>>> from django.db.models import Q
>>> con = Q() #1. 实例化一个Q()查询类
>>> con.connector = "OR" #2. 指定使用‘OR’条件
>>> con.children.append(('qq__contains','123')) #3. qq字段中包含‘123’
>>> con.children.append(('name__contains','name0')) #4. name字段中包含‘naem0’
>>> con
<Q: (OR: ('qq__contains', '123'), ('name__contains', 'name0'))>
#5. 查找name字段中包含‘naem0’或qq字段包含‘123’的所有条目
>>> models.Customer.objects.values('qq','name').filter(con)
# and和or结合查询
#1. 导入模块
>>> from crm import models
>>> from django.db.models import Q
#2. q1:查询id=1或者id=2的所有条目 (or条件)
>>> q1 = Q()
>>> q1.connector = 'OR'
>>> q1.children.append(('id',1))
>>> q1.children.append(('id',2))
#3. q2:查询id=1的所有条目 (or条件)
>>> q2 = Q()
>>> q2.connector = 'OR'
>>> q2.children.append(('id',1))
#4. con:结合q1和q2条件结果是查询id=1的所有条目 (结合q1,q2的and条件)
>>> con = Q()
>>> con.add(q1,'AND')
<Q: (OR: ('id', 1), ('id', 2))>
>>> con.add(q2,'AND')
<Q: (AND: (OR: ('id', 1), ('id', 2)), ('id', 1))>
>>> models.Customer.objects.values('qq','name').filter(con)
<QuerySet [{'qq': '123456765432', 'name': 'haha'}]>