深入理解Queryset源码之内置缓存特性
一 背景
之前做了篇笔记,简单介绍了下Queryset的两大性质—–缓存和惰性,当时初学Django,也并没有阅读下QuerySet的底层源码。
现做此笔记,详细的从代码角度理解下什么样的操作会去查询数据库,什么样的操作会去创建清除QuerySet内置的缓存。
浏览了网上的一些博客,大多数都只是字面谈了谈Queryset的缓存和惰性两大性质,有些写的也是错的,因此我就自己去源码寻找正确的答案,毕竟自己经历一番,才会更加熟悉。
二 查询数据库,产生缓存列表的代码分析
首先进入到QuerySet类,from django.db.models import QuerySet
{width=90%}
说明:我们在实例方法__init__
中可以找到存放缓存的属性的定义
接下来,我们需要找到查询数据库产生缓存的地方
{width=90%}
知道了缓存产生的函数,我们就可以依次去从源码中找哪些地方调用了该函数。
1.__getstate__
使用pickle模块等序列化queryset时候,会去查询数据库,生成缓存列表,例如将查询集序列化到缓存redis中。
{width=90%}
2.__getitem__
方法中,对queryset进行索引或者切片会去查询数据库,生成缓存列表
{width=90%}
3.__bool__
方法中,调用if else来对查询集进行判断的时候,例如if queryset:
,此时会去查询数据库,
因此当已经存在缓存列表时,使用if queryset.exists()
而不是直接if queryset
。这样不会再次查询数据库。
{width=90%}
4.__iter__
方法中,返回一个迭代器的时候,也就是在for循环时,会去查询数据库,生成缓存列表
{width=90%}
5.__repr__
方法中,通过print
打印或者调用queryset.__repr__
均会调用__repr__
,因为其中并没有定义__str__
。
{width=90%}
说明: 其中回调用list(self[:REPR])方法,实际上调用了__getitem__
内置方法,然后调用了__iter__
内置方法,返回一个迭代器。
三 清空缓存的函数
1.delete删除实例的时候,清空缓存{width=90%}
2.update更新实例的时候,清空缓存
{width=90%}
那么到这里,针对QuerySet的缓存设置和删除的相关函数已经基本了解,但是在深入想一下,如果我不手动调用delete或者update方法,那么缓存如何清除呢?
其实,QuerySet内置的缓存是List类型的,也就是存放在内存中,那么根据Python三大内存回收机制,一段时间不使用缓存列表了,则Python解释器会自动帮你回收内存资源,这样也就自然的清除了。
所以我大胆猜测,前端发送的请求,如果多个请求间隔小,则利用QuerySet的缓存特性,则可以减少数据库的查询次数。就像self.get_queryset()
原理函数一样,调用缓存。
四 不产生缓存的方法
这里先主要介绍下iterator()方法,其实还有exists()也不会生成缓存
{width=90%}
{width=90%}
分析:因为yield关键字存在,所以它所在的方法就是一个生成器。生成器是一个特殊的迭代器,依赖惰性性质,需要生成数据时候才会生成数据,不占用过多内存。迭代器内部定义了__iter__方法和__next__方法。
具体想要了解迭代器和生成器的区别,可以参考以下博客:
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!