热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

有效使用Django的QuerySets

有效使用Django的QuerySets
  对象关系映射 (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,可能会造成额外的数据库查询。

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

以上就是有效使用Django的QuerySets的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • Django框架下的对象关系映射(ORM)详解
    在Django框架中,对象关系映射(ORM)技术是解决面向对象编程与关系型数据库之间不兼容问题的关键工具。通过将数据库表结构映射到Python类,ORM使得开发者能够以面向对象的方式操作数据库,从而简化了数据访问和管理的复杂性。这种技术不仅提高了代码的可读性和可维护性,还增强了应用程序的灵活性和扩展性。 ... [详细]
  • 本文为初学者提供了一条清晰的学习路线,帮助他们逐步成长为优秀的Web开发人员。通过十个关键步骤,涵盖从基础到高级的各个方面,确保每位学习者都能找到适合自己的学习方向。 ... [详细]
  • 本文介绍了如何通过安装 sqlacodegen 和 pymysql 来根据现有的 MySQL 数据库自动生成 ORM 的模型文件(model.py)。此方法适用于需要快速搭建项目模型层的情况。 ... [详细]
  • 如何在Django框架中实现对象关系映射(ORM)
    本文介绍了Django框架中对象关系映射(ORM)的实现方式,通过ORM,开发者可以通过定义模型类来间接操作数据库表,从而简化数据库操作流程,提高开发效率。 ... [详细]
  • 本文详细介绍了如何在 Django 项目中使用 Admin 管理后台,包括创建超级用户、启动项目、管理数据模型和修改用户密码等步骤。 ... [详细]
  • 在Ubuntu系统中配置Python环境变量是确保项目顺利运行的关键步骤。本文介绍了如何将Windows上的Django项目迁移到Ubuntu,并解决因虚拟环境导致的模块缺失问题。通过详细的操作指南,帮助读者正确配置虚拟环境,确保所有第三方库都能被正确识别和使用。此外,还提供了一些实用的技巧,如如何检查环境变量配置是否正确,以及如何在多个虚拟环境之间切换。 ... [详细]
  • Django新手指南:第三步——构建你的首个项目
    在本教程中,我们将引导你完成创建第一个Django应用的步骤。通过实际操作,你将逐步了解Django框架的核心概念和基本功能。从项目结构到视图和模板的实现,我们将详细介绍每个环节,帮助你快速上手并构建出一个功能完整的Web应用。 ... [详细]
  • 本文详细解析了MySQL中常见的几种错误,并提供了具体的解决方法,帮助开发者快速定位和解决问题。 ... [详细]
  • DRF框架中Serializer反序列化验证机制详解:深入探讨Validators的应用与优化
    在DRF框架的反序列化验证机制中,除了基本的字段类型和长度校验外,还常常需要进行更为复杂的条件限制校验。通过引入`validators`模块,可以实现自定义校验逻辑,如唯一字段校验等。本文将详细探讨`validators`的使用方法及其优化策略,帮助开发者更好地理解和应用这一重要功能。 ... [详细]
  • 基于 Bottle 框架构建的幽默应用 —— Python 实践 ... [详细]
  • PyCharm 作为 JetBrains 出品的知名集成开发环境(IDE),提供了丰富的功能和强大的工具支持,包括项目视图、代码结构视图、代码导航、语法高亮、自动补全和错误检测等。本文详细介绍了 PyCharm 的高级使用技巧和程序调试方法,旨在帮助开发者提高编码效率和调试能力。此外,还探讨了如何利用 PyCharm 的插件系统扩展其功能,以满足不同开发场景的需求。 ... [详细]
  • 利用Python与Android进行高效移动应用开发
    通过结合Python和Android,可以实现高效的移动应用开发。首先,需要安装Scripting Layer for Android (SL4A),这是一个开源项目,旨在为Android系统提供脚本语言支持。SL4A不仅简化了开发流程,还允许开发者使用Python等高级语言编写脚本,从而提高开发效率和代码可维护性。此外,SL4A还支持多种其他脚本语言,进一步扩展了其应用范围。通过这种方式,开发者可以快速构建功能丰富的移动应用,同时保持较高的灵活性和可扩展性。 ... [详细]
  • 在 Ubuntu 16.04 环境下,使用 Django 2.0、uWSGI 和 Nginx 部署项目时,如果在执行 uWSGI 配置文件时遇到“No module named 'django'”错误,可以通过以下步骤进行排查和解决。该错误通常由 Python 环境配置不当或依赖项缺失引起。建议检查虚拟环境是否正确激活,Django 是否已安装,以及 uWSGI 是否指向了正确的 Python 解释器。 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • Django框架进阶教程:掌握Ajax请求的基础知识与应用技巧
    本教程深入探讨了Django框架中Ajax请求的核心概念与实用技巧,帮助开发者掌握异步数据交互的方法,提升Web应用的响应速度和用户体验。通过实例解析,详细介绍了如何在Django项目中高效实现Ajax请求,涵盖从基础配置到复杂场景的应用。 ... [详细]
author-avatar
平凡我86
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有