Django lazy load 懒加载 倒序查询

编程入门 行业动态 更新时间:2024-10-10 05:25:58

Django lazy load 懒<a href=https://www.elefans.com/category/jswz/34/1771433.html style=加载 倒序查询"/>

Django lazy load 懒加载 倒序查询

Django orm默认懒加载

 

Django orm默认使用的懒加载,即使用的时候才去访问数据库,且每次默认取最少的数据,当然这样有好处也有坏处...

  • 坏处:
    会导致频繁的查询数据库,如涉及到外键的时候,会先去取需要的数据集,再取外键的数据集,等于访问了两次数据库,那取n条数据就访问了n*n次数据库
    如查询语句:
    models.Article.objects.all() 当Article表中关联author、tag、categroy等外键字段时,你取一条数据,他需要去访问4次数据库,三外键加本身。
  • 好处:

    显然的当你执行:
    models.Article.objects.all() 这样的语句,如果一次全部查询把所有数据给你返回,你是小网站,数据小无所谓,数据大了内存就爆炸了!

    django orm的策略是,懒加载:
    即:res = models.Article.objects.all()这样的所有查询、obj = models.Article('title'='xxx', 'body' = 'xxx') 等语句时。
    并没有真正去数据库操作取出、生成数据,而是生成Query_set迭代对象

     .create() 和.update()语句会保存的同时直接去数据库创建
    而在执行res[0].title、res[10],body 还有obj.save()这样的语句时才真正的去执行SQL语句,操作数据库,取数据,保存数据。
    第一个很直观的一堆Query_set对象中没有取回数据,当然占用内存就小很多了。
    而当每次查询回来数据,Django就会把这些数据保存在cache中,当你下次使用时,不会去数据库再次查询,而是去cache里面取。

二、升降序、结果集
  • 结果集

    Django 的数据查询基于构建结果集及对结果集进行取值. 结果集是独立于数据库的符合某个查询条件的一组数据对象的集合.这是一个惰性集合:在对该集合取值之前,无法知道该集合有哪些成员.
     
    要生成一个满足你需求的结果集,首先要得到一个描述给定类型的所有对象的初始结果集.这个初始结果集可以通过一系列函数进行更精细的优化处理.当经过处理后的结果集符合你的要求时, 就可以对它进行取值操作(使用迭代操作,slicing操作,或一系列其它技术), 以得到一个你需要的对象或对象的列表.
     
    获得初始结果集
    每个 Django model 都有一个与生俱来的管理器对象 objects, 管理器最重要的角色就是作为初始结果的来源. 一个管理器就是一个描述给定类型所有对象的特殊的初始结果集. Article.objects 就是包含所有 Poll 对象的一个初始结果集. 它唯一特殊之处在于它不能被取值. 要克服此限制, 管理器对象有一个 all() 方法. 该方法生成一个 可以 被取值的初始结果集的拷贝:
     
    res = models.Article.objects.all()
    Article.objects.all()[:-11:-1] 取最后10个对象
    Article.objects.all()[0:10] 取前10个对象
    结果集对象是惰性对象 - 也就是说,他们不是 真正的 包含他们表示对象的集合 (或列表). Python 的协议魔法让结果集看起来是一个可迭代,可切片的对象. 事实上在幕后, Django 使用了缓存技术..
     
    如非要把它们变成列表。那只能强制取值了:
     
    querylist = list(Article.objects.all()) #这儿可以理解为 list(dict.keys())一样的感觉,把<class 'dict_keys'>对象变为列表
    不过,最好不要这么做,特别是在该集合相当大时. Django 每创建一个对象都需要内存,将占用相当大的内存.
     
    可理解为生成器 genrator = (x for x in range(10000000)) 和列表生成式 list = [i for i in range(100000000)] 的区别
    前者是一个生成器对象,当需要数据时,根据规则去生成,而后者是实实在在在内存中存在的大列表
     

    2.2 升降序
    .order_by()语句 order_by('id')’默认升序 ASC
    在order_by('-id')和order_by('-pub_time') 排序字段名前加 - 减号表示降序 DESC
    res = models.Article.objects.all().order_by('id') 按照id正向排序
  • reverse()方法反向排序

    res.reverse()[:5]
    注意,这与Python 中从一个序列的末尾进行切片有点不一样。上面的例子将首先返回最后一个元素,然后是倒数第二个元素,依此类推。如果我们有一个Python序列,当我们查看list[-5:]时,我们将一下子得到倒数五个元素。Django不支持这种访问模型(从末尾进行切片),因为它不可能利用SQL高效地实现。
     
    同时还要注意,reverse() 应该只在一个已经定义排序的QuerySet上调用(例如,在一个定义了默认排序的模型上,或者使用order_by()的时候)。如果QuerySet没有定义排序,调用reverse()将不会有任何效果

三、倒序查询

本来这片文章的起因就是作者在写一个查询语句,我只需要最后更新的10个数据。我就在想如果是用SQL语句很简单:

但是如果使用Query_set 来查询,不管我是正序还是倒序,都会返回巨大的数据量。就开始去了解Django的Query_set 查询策略

from django.db import modelsclass Article(models.Model):title = models.CharField(max_length= 64)body = models.TextField()pub_time = models.DateTimeField(auto_now_add= True)class Meta:get_latest_by = 'pub_time'
  • 几种反向查询策略:以上表为例
    order_by() 语句:
    models.Article.objects.all().order_by('-id) 或者 order_by('-pub_time')
     
    反向切片访问:
    models.Article.objects.fiter(id__gte=0)[::-1] 完全反向切片
     
    reverse()函数
    models.Article.objects.all().order_by('id').reverse()
3.2 访问最后一个元素
  • 通过.frist()访问第一个元素,.last()访问最后一个元素.
    models.Article.objects.all().last()

  • latest(self, *fields, field_name=None) 函数访问
    根据 model 的 'get_latest_by' 选项或可选的字段名参数返回最新的对象. 例子:
     
    Article.objects.latest()
     
    Article.objects.latest('expire_date')

如果模型的Meta指定get_latest_by,则可以将field_name参数留给earliest()或者 latest()。默认情况下,Django将使用get_latest_by中指定的字段。

get_latest_by

由于Django的管理方法中有个lastest()方法,就是得到最近一行记录。如果你的数据模型中有 DateField 或 DateTimeField 类型的字段,你可以通过这个选项来指定lastest()是按照哪个字段进行选取的。

一个 DateField 或 DateTimeField 字段的名字. 若提供该选项, 该模块将拥有一个 get_latest() 函数以得到 "最新的" 对象(依据那个字段):

四、字段查找

exact、iexact

exact:精确匹配。区分大小写

例如:

Entry.objects.get(id__exact=14)

Entry.objects.get(id__exact=None)

iexact:不区分大小写的精确匹配

例如:

Blog.objects.get(name__iexact='beatles blog')

Blog.objects.get(name__iexact=None)

contains、icontains

contains:包含,大小写敏感

例如:

Entry.objects.get(headline__contains='Lennon')

icontains:包含,大小写不明感.

例如:

Entry.objects.get(headline__icontains='Lennon')

in

在一个给定的列表中.

Example:

Entry.objects.filter(id__in=[1, 3, 4])

gt、gte、lt、lte

gt:大于

例子:

Entry.objects.filter(id__gt=4)

gte:大于或等于

lt:小于

lte:小于或等于

startswith、istartswith、endswith、iendswith

startswith:区分大小写,开始位置匹配

例如:

Entry.objects.filter(headline__startswith='Will')

istartswith:不区分大小写,开始位置匹配

endswith:区分大小写,结束位置匹配

iendswith:不区分大小写,结束位置匹配

range

范围

例如:

import datetime

start_date = datetime.date(2005, 1, 1)

end_date = datetime.date(2005, 3, 31)

Entry.objects.filter(pub_date__range=(start_date, end_date))

等价SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

year、month、day

year: 返回精确的年份

例如:

Entry.objects.filter(pub_date__year=2005)

等价SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';

month: 对于月份时间字段,匹配一个整数从1 (January)到 12 (December).

day: 对于日期和日期时间字段,具体到某一天的匹配。取一个整数的天数。

isnull

值为 True 或False, 相当于SQL语句IS NULL和IS NOT NULL.

例如:

Entry.objects.filter(pub_date__isnull=True)

等价SQL:

SELECT ... WHERE pub_date IS NULL;

转载于:.html

更多推荐

Django lazy load 懒加载 倒序查询

本文发布于:2024-02-14 05:30:04,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762273.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:加载   Django   lazy   load

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!