首页 >后端开发 >Python教程 >需要修复的常见 Django ORM 错误

需要修复的常见 Django ORM 错误

Barbara Streisand
Barbara Streisand原创
2025-01-04 00:49:401009浏览

Common Django ORM Mistakes to fix

Django ORM 是 django 最强大的功能之一。它抽象化了与数据库交互的大部分复杂性,让开发人员可以使用 Pythonic 语法而不是原始 SQL 来操作数据。所有这些 ORM 函数都会生成 SQL 查询,如果处理不当,这些查询可能会成为瓶颈。
本博客重点介绍了使用 Django ORM 时的常见错误,并提供了保持查询高效、可维护和高性能的技巧。

1. N 1 查询问题

当您的代码触发一个查询来获取一组记录,然后再次运行 N 个附加查询来获取相关数据时,就会出现 N 1 查询问题。

blogs = Blog.objects.all()    # 1 Query
for blog in blogs:
    print(blog.author.name)   # N additional queries

在上面的示例中,在循环内访问 blog.author.name 会导致 Django 单独获取每个博客的作者记录,从而导致 N 个额外的查询。

如何解决
对单个相关对象(例如,ForeignKey 或 OneToOneField)使用 select_lated,因为它执行 SQL JOIN 以在一个查询中检索主对象及其相关对象。对于多对多、多对一或反向关系,请使用 prefetch_lated,它在单独的查询中获取相关数据,但在 Python 中有效地将它们组合起来,避免 N 1 问题。

# With select_related
blogs = Blog.objects.select_related('author').all()

# With prefetch_related
authors = Author.objects.prefetch_related('blogs').all()

2. 过度使用.all()和.filter()

开发人员经常链接多个过滤器或使用 .all() ,然后对同一查询集重复查询:

blogs = Blog.objects.all()
active_blogs = blogs.filter(is_archived=False)
popular_blogs = blogs.filter(views__gte=1000)

尽管 Django 尝试通过仅在需要时延迟评估查询集来优化查询集,但对同一查询集数据重复调用过滤器仍然会导致对数据库不必要的命中。

如何解决
在一条语句中组合过滤器允许 django 生成单个 SQL 查询。

popular_active_blogs = Blog.objects.filter(is_archived=False, views__gte=1000)

3. 不利用values()或values_list()

有时我们只需要特定字段而不是模型的所有字段数据。在此期间使用 .values().values_list() 可以更高效。

titles = Blog.objects.values('title')
or
titles = Blog.objects.values_list('title', flat=True)
# values() returns a list of dictionaries.
# values_list() can return tuples or flat values if flat=True is provided.

通过仅获取所需的列,可以减少从数据库传输的数据量,从而提高性能。

4. 低效的聚合和注释

重复调用 .aggregate().annotate() 可能会导致多次查询。具有多个注释的复杂查询可能会导致 SQL 查询效率低下,从而可能导致繁重的数据库操作。

# Example of multiple aggregate
total_count = Blog.objects.aggregate(Count('id'))
author_count = Blog.objects.aggregate(Count('author'))
average_views = Blog.objects.aggregate(Avg('views'))

推荐

blogs = Blog.objects.all()    # 1 Query
for blog in blogs:
    print(blog.author.name)   # N additional queries

5. 不使用数据库索引

索引使数据库能够快速定位和检索数据,避免缓慢的全表扫描,从而提高查询性能。索引优化了过滤、排序和连接等操作,使得对频繁访问的字段的查询速度更快。频繁查询字段上缺少数据库索引会大大降低性能。
如何在 Django 中添加索引

# With select_related
blogs = Blog.objects.select_related('author').all()

# With prefetch_related
authors = Author.objects.prefetch_related('blogs').all()

索引可以加快读取速度,但会减慢写入速度。因此,只对那些经常需要查询的字段建立索引。

6. 不使用缓存

当我们必须查询计算成本昂贵或很少更改的数据时,请使用缓存。即使缓存 5 分钟,也可以节省重复查询、复杂计算和不经常更改的查询。

blogs = Blog.objects.all()
active_blogs = blogs.filter(is_archived=False)
popular_blogs = blogs.filter(views__gte=1000)

7. 原始 SQL

有时,Django ORM 无法有效地表达复杂的查询或批量操作。虽然 Django 提供 .extra() 或 .raw(),但原始 SQL 使用应该是最后的手段,因为它:

  • 失去了 ORM 的许多好处
  • 可能导致不可读或容易出错的代码

确保输入得到正确清理并保持原始 SQL 查询可维护。

应用这些技巧,您将提高 Django 应用程序的性能,同时保持代码整洁和可维护。并建议在开发环境中使用 Django 调试工具栏 来监控和分析执行的查询数量、执行时间和 SQL 语句。

以上是需要修复的常见 Django ORM 错误的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn