IT加油站

Django 测试中用 django-query-guard 阻止 N+1 查询

17浏览 1天前 软件教程 MA122961

原文:https://dev.to/atiqur_rahman_5998740c55f/how-to-stop-n1-database-queries-in-django-tests-with-django-query-guard-dk2(作者 @atiqur_rahman_5998740c55f)

N+1 数据库查询和悄无声息的查询数量增长会严重影响 Django 应用的性能。遗憾的是,这些问题往往发现得太晚——直到生产环境服务器日志或 APM 仪表盘上才暴露出来。

为了解决这个问题,`django-query-guard` 应运而生——它是一个开源的 Pytest 插件,将数据库性能检查直接集成到自动化测试套件中。


问题:悄无声息的 N+1 查询

在 Django 中,ORM 让获取关联模型变得轻而易举,但也极其容易意外写出 N+1 循环:

# N+1 查询事故
# 获取 100 个用户(1 次查询),然后为每个 profile 单独执行 100 次查询!
# 总计:101 次数据库查询!
users = User.objects.all()
profiles = [user.profile.bio for user in users]


解决方案:django-query-guard

不再依赖人工代码审查,django-query-guard 将查询限制和 N+1 防护转化为可强制执行的 Pytest 断言:

import pytest

@pytest.mark.django_db
@pytest.mark.query_guard(max_queries=2, detect_n_plus_one=True)
def test_user_profiles_api(client):
    response = client.get("/api/users/")
    assert response.status_code == 200


如果接口意外执行了 101 次查询而非 2 次,Pytest 会立即失败,并给出重复执行的 SQL 语句的精确明细!

核心特性

  • Pytest 标记集成@pytest.mark.query_guard(max_queries=N)
  • 智能 SQL 归一化:参数变体过滤可避免对具有相同参数的有意重复查询产生误报。
  • 多数据库支持:监控所有已配置的 Django 数据库连接(默认库、副本库等)中的查询。
  • HTML 查询报告:测试运行后生成深色主题 HTML 报告(pytest --query-guard-report=report.html)。
  • 趋势历史追踪:基于 JSON 的运行历史记录,支持跨测试构建的回归检测(pytest --query-guard-trend=.query_guard_history.json)。
  • 广泛兼容性:已在 Python 3.10–3.14 和 Django 4.0–6.0 上全面测试。

安装与配置

从 PyPI 安装稳定版:

pip install django-query-guard


或安装开发工具:

pip install django-query-guard[dev]


生成可视化 HTML 报告

在任意测试运行后,可以生成深色主题的 HTML 查询报告:

pytest --query-guard-report=report.html


报告包含:

  • 汇总指标(总测试数、通过/失败计数、总查询数、N+1 检测数)
  • 每个测试的查询计数明细
  • 失败测试的 SQL 查询执行时长和参数明细

原文:https://dev.to/atiqur_rahman_5998740c55f/how-to-stop-n1-database-queries-in-django-tests-with-django-query-guard-dk2(作者 @atiqur_rahman_5998740c55f)

#Django #Pytest #N1查询 #数据库性能 #自动化测试