进阶正反向查询操作
通过点获取数据所在的表来查询数据,而不在点条件所在的表使代码更精简、方便
通过题目理解:所需表与上一篇文章一致
1.查询主键为1的书籍对应的出版社名称及书名 思路: 因为不能通过条件表来获取数据对象所以只能用题目中涉及的另一张表 再判断在当前表下去查询数据是正向还是反向(记住口诀:正向用外键字段,反向用表名小写) res = models.Publish.objects.filter(book_pk=1).values('name','book_title') 2.查询主键为1的书籍对应的作者电话号码 思路: 通过题目可知需要用到三张表,此时条件以外的两张表用哪张都可以 选作者信息表 res = models.AuthorDetail.objects.filter(duthor_book_pk=1).values('phone') 选作者表:获取数据时直接__进入下一张表 res = models.Author.objects.filter(book__pk=1).values('auther_detail__phone')
聚合查询
常见聚合函数:max、min、sum、avg、count等
MySQL中使用聚合函数前得先分组才可以,而在ORM中没有分组之前也可以使用聚合函数需要用到关键字:aggregate()
from django.db.models import Max,Min,Sum,Avg,Count # 先导模块 res = models.Book.objects.aggregate( Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pl') ) # 获取每本书的最高价格、最低价格、总价、平均价格和数量
分组查询
分组有一个特性默认只能够直接获取分组的字段其它字段需要使用方法,该特性是可以通过修改配置来忽略的:将sql_mode中only_full_group_by配置移除即可
分组关键字:annotate有两种方式
1.按照整条数据分组
models.Book.objects.annotate() # 按照一条条书籍记录分组
2.按照表中的某个字段分组
models.Book.objects.values('title').annotate() # 按照annotate之前values括号中指定的字段分组
3.实际题目理解
# 1.统计每一本书的作者个数 res = models.Book.objects.annotate(author_num=Count('authors__pk')). values('title','author_num') ''' 按整条数据分 结合了聚合函数使用,先统计个数再分组 然后获取书名和作者个数 ''' res = models.Book.objects.values('publish_id'). annotate(book_num=Count('pk')).values('publish_id','book_num') ''' 按照指定的字段分组 按照publish_id字段分组,分组后再进行统计 '''
当分组中需要用到筛选(filter)时,filter在annotate前面则就相当于MySQL中的where,filter在annotate后面则就是having
# 统计不止一个作者的图书 res = models.Book.objects.annotate(author_num=Count('authors__pk')). filter(author__num__gt=1).values('title','author_num')
Q查询与F查询
前面我们都是将字段值与某个常量做比较而不能通过两个字段直接比较值,现在django给我们提供了F查询,可以在查询中引用字段来比较同一个model实例中两个不同字段的值
使用F查询需要先导入模块
from django.db.models import F # 导入模块 # 将所有书的价格统一上涨100 res = models.Book.object.update(price=F('price')+100)
当涉及到字符串拼接的时候就单靠F是不够的还需要借助Concat和Value两个模块
# 给每本书名后面加上'热销' from django.db.models.functions import Concat from django.db.models import Value ret = models.Book.objects.all().update(title=Concat(F('title'),Value('热销'))
ORM查询优化
1.关键字only与defer
only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询
res = models.Book.objects.only('title','price') for obj in res: print(obj.title) print(obj.price) print(obj.publish_time)
而defer与only刚好相反,当数据对象点击括号内出现的字段每次都会走数据库查询,反而数据对象点击括号内没又出现的字段不会走数据库查询
res = models.Book.objects.defer('title', 'price') for obj in res: print(obj.title) print(obj.price) print(obj.publish_time)
2.关键字select_related与prefetch_related
select_related括号内只能接收外键字段(一对多 一对一) 自动连表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
res = models.Book.objects.all() for obj in res: print(obj.publish.name) # 频繁走数据库查询 res = models.Book.objects.select_related('authors') for obj in res: print(obj.publish.name)
prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
res = models.Book.objects.all() for obj in res: print(obj.publish.name) res = models.Book.objects.prefetch_related('publish') for obj in res: print(obj.publish.name)
3.ORM自身优化
django orm默认都是懒性查询
在写完orm语句后如果后续的代码没有真正的要使用这个语句的话这条orm语句是不会执行的当真正需要使用的时候才会执行
django orm自带limit分页
orm获取的数据会自动分页默认以21条的形式展示,能有效的减轻数据库端以及服务端端压力