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查询
#数据库性能
#自动化测试