查看orm内部sql语句的方法
- 看是否是queryset 对象,是的话,可直接.query查看SQL语句;
- 在django配置文件中,配置相关参数,orm查询时自动打印sql语句;
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level': 'DEBUG',
},
}
}
查询方法
all()
:查询所有结果filter(**kwargs)
:它包含了与所给筛选条件相匹配的对象get(**kwargs)
:返回数据对象,结果只有一个,没匹配到报错exclude(**kwargs)
:它包含了与所给筛选条件不匹配的对象
# 只要pk不是1的数据全部查询出来
print(models.Book.objects.exclude(pk=1))
order_by(*field)
:对查询结果排序;默认是升序,加-就是降序
print(models.Book.objects.order_by('price')) # 默认是升序
print(models.Book.objects.order_by('-price')) # 加负号就是降序
reverse()
:对查询结果反向排序
# 注:前面要先有排序才能反向
print(models.Book.objects.order_by('price').reverse())
count()
:返回数据库中匹配查询(QuerySet)
# 对查询出来的结果进行一个计数
print(models.Book.objects.count())
first()
:返回第一条记录last()
:返回最后一条记录exists()
:存在返回True,否则返回False
print(models.Book.objects.filter(pk=1000).exists())
values(*field)
:返回一个ValueQuerySet对象,运行后得到的并不是一系列
# 得到的结果是列表套字典
print(models.Book.objects.values('title','price'))
values_list(*field)
:它与values()类似
# 得到的结果是列表套元组
print(models.Book.objects.values_list('title','price'))
distinct()
:从返回结果中剔除重复纪录
# 注:去重的前提是 一定要有完全重复的数据 才能去重
print(models.Book.objects.values('title','price','create_time').distinct())
双下滑查询
__gt
:大于
# 查询价格大于200的书籍
res = models.Book.objects.filter(price__gt=200)
__lt
:小于
# 查询价格小于200的书籍
res = models.Book.objects.filter(price__lt=200)
__gte
:大于等于
# 查询价格大于等于200.22的书籍
res = models.Book.objects.filter(price__gte=200.22)
__lte
: 小于等于
# 查询价格小于等于200.22的书籍
res = models.Book.objects.filter(price__lte=200.22)
__in:
:或者
# 查询价格要么是200,要么是300,要么是666.66
res = models.Book.objects.filter(price__in=[200,300,666.66])
__range
:区间 左右都包括
# 查询价格在200到800之间的
res = models.Book.objects.filter(price__range=(200,800))
__contains
:模糊匹配
# 查询书籍名字中包含p的
res = models.Book.objects.filter(title__contains='p') # 仅仅只能拿小写p
res = models.Book.objects.filter(title__icontains='p') # 忽略大小写
__startswith
:以…开头
# 查询书籍是以三开头的
res = models.Book.objects.filter(title__startswith='三')
- ``__endswith`:以…结尾
# 查询书籍是以三结尾的
res = models.Book.objects.filter(title__endswith='三')
__year
:查询年相关的
# 查询出版日期是2017的年(**)
res = models.Book.objects.filter(create_time__year='2017')
多表查询
一对多
增
# publish_id传数字:
models.Book.objects.create(title='三国演义', price=189.99, publish_id=1)
# publish直接传出版社对象:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦', price=999.99, publish=publish_obj)
改
# 传数字的:
models.Book.objects.filter(pk=1).update(publish_id=3)
# 传对象的:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
删
# 默认都是级联更新 级联删除
models.Publish.objects.filter(pk=2).delete()
多对多
增(add)
既可以传数字也可以传对象并且支持一次性传多个,逗号隔开即可
# 要给主键为1的书籍添加两个作者
# 1. 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
book_obj.authors.add(2, 3)
# 2. 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1, author_obj2)
改(set)
- set中要传可迭代对象,可迭代对象中 可以是多个数字组合也可以是多个对象组合;
- 数字与对象不要混着用!!!
# 将主键为1的书籍对象,作者修改为2、3
# 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2, ])
book_obj.authors.set([2, 3])
# 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj, ])
book_obj.authors.set([author_obj, author_obj1, author_obj2])
删(remove | clear)
对象点击多对多虚拟字段 会直接跨到多对多的第三张表
- remove支持传数字,对象,并且可以传多个;
- clear不需要传任何参数
# 传数字:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
book_obj.authors.remove(1, 2)
# 传对象:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1, author_obj2)
# 什么都不传: 将xx跟xx的关系全部清空
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear() # 清空当前书籍与作者的所有关系
跨表查询
- 正向与反向概念
正向查询按外键字段查,反向查询按表名小写
- 一对一
- 正向:author—关联字段在author表里—>authordetail 按字段
- 反向:authordetail—关联字段在author表里—>author 按表名小写
- 一对多
- 正向:book—关联字段在book表里—>publish 按字段
- 反向:publish—关联字段在book表里—>book 按表名小写_set.all() 因为一个出版社对应着多个图书
- 多对多
- 正向:book—关联字段在book表里—>author 按字段
- 反向:author—关联字段在book表里—>book 按表名小写_set.all() 因为一个作者对应着多个图书
子查询
将一张表的查询结果当做另外一个查询语句的条件
当反向查询的结果有多个时,要在后面加上_set;
# 1. 查询书籍id是1的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish.name)
# 2. 查询书籍id是2的作者姓名
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors) # app01.Author.None
print(book_obj.authors.all())
res = book_obj.authors.all()
for r in res:
print(r.name)
# 3. 查询作者是jason的家庭住址
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.addr)
# 4. 查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set) # app01.Book.None
print(publish_obj.book_set.all())
# 5. 查询作者是jason的写过的所有的书籍
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set) # app01.Book.None
print(author_obj.book_set.all())
# 6. 查询电话号码是130的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first()
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)
# 7. 查询书籍id为1的作者的电话号码
book_obj = models.Book.objects.filter(pk=1).first()
author_list = book_obj.authors.all()
for author_obj in author_list:
print(author_obj.author_detail.phone)
连表操作(基于__)
- 只要表里面有外键字段, 你就可以无限制跨多张表
- 如:
外键字段1外键字段2...外键字段__普通字段n
# 1. 查询jason作者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('author_detailphone', 'author_detailaddr')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res1)
# 2. 查询jason这个作者的年龄和手机号
# 正向
res = models.Author.objects.filter(name='jason').values('age', 'author_detail__phone')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(authorname='jason').values('phone', 'authorage')
print(res1)
# 3. 查询手机号是130的作者年龄
# 正向
res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
print(res)
# 反向
res1 = models.Author.objects.filter(author_detail__phone=130).values('age')
print(res1)
# 4. 查询书籍id是1的作者的电话号码
res = models.Book.objects.filter(pk=1).values('authorsauthor_detailphone')
print(res)
# 5. 查询出版社为北方出版社的所有图书的名字和价格
res = models.Publish.objects.filter(name='北方出版社').values('booktitle', 'bookprice')
print(res)
# 6. 查询北方出版社出版的价格大于19的书
res = models.Book.objects.filter(pricegt=19, publishname='北方出版社').values('title', 'publish__name')
print(res)
聚合查询(aggregate)
最大,最小,个数,平均,总和
aggregate(后面可跟多个函数)
from django.db.models import Max, Min, Count, Avg, Sum
res = models.Book.objects.aggregate(Sum('price'))
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'), Min('price'), Count('pk'), Avg('price'), Sum('price'))
分组查询(annotate)
models.那个表名就以那个分组
from django.db.models import Max, Min, Count, Avg, Sum
# 1. 统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num', 'title')
print(res)
# 2. 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(mmp=Min('book__price')).values('name', 'mmp')
print(res)
# 3. 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
print(res)
# 4. 查询各个作者出的书的总价格
res = models.Author.objects.annotate(sp=Sum('book__price')).values('name', 'sp')
print(res)
F查询
本质就是从数据库中获取某个字段的值
from django.db.models import F
# 1. 查询卖出数量
res = models.Book.objects.filter(kucun__gt=F('maichu'))
print(res)
# 2. 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun') + 1000)
# 3. 把所有书名后面加上'新款'
from django.db.models import Value
from django.db.models.functions import Concat
ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
# models.Book.objects.update(title=F('title') + '新款') # 不能这么写
Q查询
默认and,可人为改为 or , not
from django.db.models import Q
# 查询书籍名称是三国演义或者价格是444.44
# and:
res = models.Book.objects.filter(title='三国演义', price=444.44) # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'), Q(price=444)) # 如果用逗号 那么还是and关系
# or:
res2 = models.Book.objects.filter(Q(title='三国演义') | Q(price=444))
# not:
res3 = models.Book.objects.filter(~Q(title='三国演义') | Q(price=444))
# Q高级用法(了解)
q = Q()
q.connector = 'or' # 修改查询条件的关系 默认是and
q.children.append(('title__contains', '三国演义')) # 往列表中添加筛选条件
q.children.append(('price__gt', 444)) # 往列表中添加筛选条件
res = models.Book.objects.filter(q) # filter支持你直接传q对象 但是默认还是and关系
print(res)
查询优化
orm内所有的语句操作都是惰性查询
只会在你真正需要数据的时候才会走数据库,这样有利于减轻数据库压力
- only与defer
- only
- 会将only()内的字段一次性的查出来返封装进一个对象中;
- 你查only内的数据,不管取值多少次,也只会走一次数据库 ;
- 你查的不是only内的数据,不会报错也会返回数据,但是会频繁的走数据库
- defer
- 会将不是defer()内的所有字段信息全查出来封装进对象中;
- 你查询()内的字段会频繁的走数据库,对手库python的压力比较大,反之只走一次库
- only
- select_related与prefetch_related
- select_related
- 会将括号内外键字段所关联的那张表直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作;
- 从而降低你跨表查询 数据库的压力;
select_related括号只能放外键字段(一对一、一对多)
。
- prefetch_related
- 不主动连表操作(但是内部给你的感觉像是连表操作了);
- 会将book表中的publish_id全部拿来;
- 再去publish表中将id对应的所有的数据取出。
- 区别:
- select_related需要连表,但只走一次数据库;连表会花时间
- prefech_related不用连表,括号内有几个外键字段 就会走几次数据库查询操作
- select_related
评论区