Django框架 querySet功能解析


Posted in Python onSeptember 04, 2019

可切片

使用Python 的切片语法来限制查询集记录的数目 。它等同于SQL 的LIMIT 和OFFSET 子句。

>>> Entry.objects.all()[:5] # (LIMIT 5)
Entry.objects.all()[5:10] # (OFFSET 5 LIMIT 5)

不支持负的索引(例如Entry.objects.all()[-1])。通常,查询集 的切片返回一个新的查询集 —— 它不会执行查询。

 

可迭代

articleList=models.Article.objects.all()
for article in articleList:
  print(article.title) 

惰性查询

查询集 是惰性执行的 —— 创建查询集不会带来任何数据库的访问。你可以将过滤器保持一整天,直到查询集 需要求值时,Django 才会真正运行这个查询。

queryResult=models.Article.objects.all() # not hits database
print(queryResult) # hits database 
for article in queryResult:
  print(article.title)  # hits database

一般来说,只有在“请求”查询集 的结果时才会到数据库中去获取它们。当你确实需要结果时,查询集 通过访问数据库来求值。 关于求值发生的准确时间,参见何时计算查询集。

缓存机制

每个查询集都包含一个缓存来最小化对数据库的访问。理解它是如何工作的将让你编写最高效的代码。

在一个新创建的查询集中,缓存为空。首次对查询集进行求值 —— 同时发生数据库查询 ——Django 将保存查询的结果到查询集的缓存中并返回明确请求的结果(例如,如果正在迭代查询集,则返回下一个结果)。接下来对该查询集 的求值将重用缓存的结果。

请牢记这个缓存行为,因为对查询集使用不当的话,它会坑你的。例如,下面的语句创建两个查询集,对它们求值,然后扔掉它们:

print([a.title for a in models.Article.objects.all()])
print([a.create_time for a in models.Article.objects.all()])

这意味着相同的数据库查询将执行两次,显然倍增了你的数据库负载。同时,还有可能两个结果列表并不包含相同的数据库记录,因为在两次请求期间有可能有Article被添加进来或删除掉。为了避免这个问题,只需保存查询集并重新使用它: 

queryResult=models.Article.objects.all()
print([a.title for a in queryResult])
print([a.create_time for a in queryResult])

何时查询集不会被缓存?

查询集不会永远缓存它们的结果。当只对查询集的部分进行求值时会检查缓存, 如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存。所以,这意味着使用切片或索引来限制查询集将不会填充缓存。

例如,重复获取查询集对象中一个特定的索引将每次都查询数据库:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again

然而,如果已经对全部查询集求值过,则将检查缓存:

>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache

下面是一些其它例子,它们会使得全部的查询集被求值并填充到缓存中:

>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)

注:简单地打印查询集不会填充缓存。

queryResult=models.Article.objects.all()
print(queryResult) # hits database
print(queryResult) # hits database 

exists()与iterator()方法

exists:

简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些 数据!为了避免这个,可以用exists()方法来检查是否有数据:

if queryResult.exists():
  #SELECT (1) AS "a" FROM "blog_article" LIMIT 1; args=()
    print("exists...")

iterator:

当queryset非常巨大时,cache会成为问题。

处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法 来获取数据,处理完数据就将其丢弃。

objs = Book.objects.all().iterator()
# iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs:
  print(obj.title)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
  print(obj.title)

当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使 #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询。

总结:

queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基础教程之常用运算符
Aug 29 Python
Python正则表达式非贪婪、多行匹配功能示例
Aug 08 Python
Python操作Redis之设置key的过期时间实例代码
Jan 25 Python
批量将ppt转换为pdf的Python代码 只要27行!
Feb 26 Python
用tensorflow搭建CNN的方法
Mar 05 Python
Python图像滤波处理操作示例【基于ImageFilter类】
Jan 03 Python
Python PyQt5 Pycharm 环境搭建及配置详解(图文教程)
Jul 16 Python
基于python 微信小程序之获取已存在模板消息列表
Aug 05 Python
pytorch中使用cuda扩展的实现示例
Feb 12 Python
Python安装与卸载流程详细步骤(图解)
Feb 20 Python
python实例化对象的具体方法
Jun 17 Python
python如何调用百度识图api
Sep 29 Python
Django框架 查询Extra功能实现解析
Sep 04 #Python
Django框架 Pagination分页实现代码实例
Sep 04 #Python
python 动态迁移solr数据过程解析
Sep 04 #Python
Django框架 信号调度原理解析
Sep 04 #Python
Django Admin中增加导出Excel功能过程解析
Sep 04 #Python
Django Admin中增加导出CSV功能过程解析
Sep 04 #Python
Python 自动登录淘宝并保存登录信息的方法
Sep 04 #Python
You might like
php date与gmdate的获取日期的区别
2010/02/08 PHP
ThinkPHP字符串函数及常用函数汇总
2014/07/18 PHP
php中socket通信机制实例详解
2015/01/03 PHP
Zend Framework动作助手Url用法详解
2016/03/05 PHP
PHP中key和current,next的联合运用实例分析
2016/03/29 PHP
thinkphp利用模型通用数据编辑添加和删除的实例代码
2016/11/20 PHP
修改yii2.0用户登录使用的user表为其它的表实现方法(推荐)
2017/08/01 PHP
ThinkPHP3.2.3框架邮件发送功能图文实例详解
2019/04/23 PHP
使用node.js 获取客户端信息代码分享
2014/11/26 Javascript
深入理解事件冒泡(Bubble)和事件捕捉(capture)
2016/05/28 Javascript
js 将图片连接转换成base64格式的简单实例
2016/08/10 Javascript
D3.js实现柱状图的方法详解
2016/09/21 Javascript
Vue2 使用 Echarts 创建图表实例代码
2017/05/18 Javascript
创建简单的node服务器实例(分享)
2017/06/23 Javascript
利用SpringMVC过滤器解决vue跨域请求的问题
2018/02/10 Javascript
jQuery 实现倒计时天,时,分,秒功能
2018/07/31 jQuery
JavaScript Math对象和调试程序的方法分析
2019/05/13 Javascript
JS Web Flex弹性盒子模型代码实例
2020/03/10 Javascript
vue下载二进制流图片操作
2020/10/26 Javascript
js删除对象中的某一个字段的方法实现
2021/01/11 Javascript
python3实现短网址和数字相互转换的方法
2015/04/28 Python
python如何在循环引用中管理内存
2018/03/20 Python
Python实现修改文件内容的方法分析
2018/03/25 Python
Pandas_cum累积计算和rolling滚动计算的用法详解
2019/07/04 Python
python3 批量获取对应端口服务的实例
2019/07/25 Python
对django中foreignkey的简单使用详解
2019/07/28 Python
Python爬虫程序架构和运行流程原理解析
2020/03/09 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
CSS超出文本指定宽度用省略号代替和文本不换行
2016/05/05 HTML / CSS
域名注册、建站工具、网页主机、SSL证书:Dynadot
2017/01/06 全球购物
美国时尚假发购物网站:Wigsbuy
2019/04/06 全球购物
综合素质的自我鉴定
2013/10/07 职场文书
临床医学应届生求职信
2013/11/06 职场文书
工伤事故处理协议书怎么写
2014/10/15 职场文书
还款承诺书范本
2015/01/20 职场文书
win10双系统怎么删除一个系统?win10电脑有两个系统删除一个的操作方法
2022/07/15 数码科技