python遍历queryset_有效使用Django的QuerySets
发布日期:2021-06-24 11:27:41 浏览次数:3 分类:技术文章

本文共 3078 字,大约阅读时间需要 10 分钟。

对象关系映射 (ORM) 使得与SQL数据库交互更为简单,不过也被认为效率不高,比原始的SQL要慢。

要有效的使用ORM,意味着需要多少要明白它是如何查询数据库的。本文我将重点介绍如何有效使用 Django ORM系统访问中到大型的数据集。

Django的queryset是惰性的

Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")

上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。

要真正从数据库获得数据,你需要遍历queryset:for person in person_set:

print(person.last_name)

Django的queryset是具有cache的

当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行(evaluation)。这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,你不需要重复运行通用的查询。

例如,下面的代码只会执行一次数据库查询:pet_set = Pet.objects.filter(species="Dog")

# The query is executed and cached.

for pet in pet_set:

print(pet.first_name)

# The cache is used for subsequent iteration.

for pet in pet_set:

print(pet.last_name)

if语句会触发queryset的执行

queryset的cache最有用的地方是可以有效的测试queryset是否包含数据,只有有数据时才会去遍历:restaurant_set = Restaurant.objects.filter(cuisine="Indian")

# `if`语句会触发queryset的执行。

if restaurant_set:

# 遍历时用的是cache中的数据

for restaurant in restaurant_set:

print(restaurant.name)

如果不需要所有数据,queryset的cache可能会是个问题

有时候,你也许只想知道是否有数据存在,而不需要遍历所有的数据。这种情况,简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些数据!city_set = City.objects.filter(name="Cambridge")

# `if`语句会执行queryset.。

if city_set:

# 我们并不需要所有的数据,但是ORM仍然会获取所有记录!

print("At least one city called Cambridge still stands!")

为了避免这个,可以用exists()方法来检查是否有数据:tree_set = Tree.objects.filter(type="deciduous")

# `exists()`的检查可以避免数据放入queryset的cache。

if tree_set.exists():

# 没有数据从数据库获取,从而节省了带宽和内存

print("There are still hardwood trees in the world!")

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

处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统进程,让你的程序濒临崩溃。

要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法来获取数据,处理完数据就将其丢弃。star_set = Star.objects.all()

# `iterator()`可以一次只从数据库获取少量数据,这样可以节省内存

for star in star_set.iterator():

print(star.name)

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

如果查询集很大的话,if 语句是个问题

如前所述,查询集缓存对于组合 if 语句和 for 语句是很强大的,它允许在一个查询集上进行有条件的循环。然而对于很大的查询集,则不适合使用查询集缓存。

最简单的解决方案是结合使用exists()和iterator(), 通过使用两次数据库查询来避免使用查询集缓存。molecule_set = Molecule.objects.all()

# One database query to test if any rows exist.

if molecule_set.exists():

# Another database query to start fetching the rows in batches.

for molecule in molecule_set.iterator():

print(molecule.velocity)

一个更复杂点的方案是使用 Python 的“ 高级迭代方法 ”在开始循环前先查看一下 iterator() 的第一个元素再决定是否进行循环。atom_set = Atom.objects.all()

# One database query to start fetching the rows in batches.

atom_iterator = atom_set.iterator()

# Peek at the first item in the iterator.

try:

first_atom = next(atom_iterator)

except StopIteration:

# No rows were found, so do nothing.

pass

else:

# At least one row was found, so iterate over

# all the rows, including the first one.

from itertools import chain

for atom in chain([first_atom], atom_set):

print(atom.mass)

防止不当的优化

queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。

使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能会造成额外的数据库查询。

所以编码时需要注意一下,如果程序开始变慢,你需要看看代码的瓶颈在哪里,是否会有一些小的优化可以帮到你。

转载地址:https://blog.csdn.net/weixin_32503531/article/details/111888024 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:linux电脑主机型号_各操作系统查看主机型号、cpu、memory的方式
下一篇:HTML5input属性选择文件,HTML 5 <input> type属性

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月21日 09时27分51秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

android设计!Android事件分发机制收藏这一篇就够了,重难点整理 2019-04-29
android语言!搞懂开源框架设计思想真的这么重要吗?3面直接拿到offer 2019-04-29
android课程表!大厂offer手到擒来,满满干货指导 2019-04-29
android网!2021中级Android开发面试解答,进阶学习资料! 2019-04-29
android自动化测试工具!为什么有人说Android开发不再吃香?建议收藏 2019-04-29
android系统架构五层!最详细的解释小白也能听懂,2年以上经验必看 2019-04-29
android线刷包!跟我一起手写EventBus吧,大厂内部资料 2019-04-29
android实战!百度、阿里、滴滴、新浪的面试心经总结,满满干货指导 2019-04-29
Android小技巧:一线互联网移动架构师NDK模块开发!含BATJM大厂 2019-04-29
android市场前景!最详细的docker中安装并配置redis,实战解析 2019-04-29
万字Android技术类校招面试题汇总,深度好文 2019-04-29
三级缓存对性能的影响,我的头条面试经历分享,3面直接拿到offer 2019-04-29
三级缓存框架问题你都了解了吗?面试必备 2019-04-29
BAT常见的20道Android面试题详解,全网疯传 2019-04-29
BAT等大厂必问技术面试题,妈妈再也不用担心我找工作了! 2019-04-29
BAT等大厂必问技术面试题,成功拿下大厂offer 2019-04-29
一眼就能看懂的Android自学手册,送大厂面经一份! 2019-04-29
一线互联网大厂中高级Android面试真题收录!大牛最佳总结 2019-04-29
一个小例子彻底搞懂Android的MVP模式到底是什么?醍醐灌顶! 2019-04-29
一个小例子彻底搞懂Android的MVP模式到底是什么?面试资料分享 2019-04-29