Use django-query-guard to make a pytest test fail when a database-backed operation exceeds a query budget or repeats the same normalized query. Mark the test with @pytest.mark.django_db and @pytest.mark.query_guard, then fix repeated relation lookups with select_related() or prefetch_related() as appropriate.
Install django-query-guard
Install the released package from PyPI:
pip install django-query-guard
PyPI lists version 0.2.1, uploaded August 7, 2026. Check the package’s current compatibility information against the Django and Python versions used by your project before adopting it; package classifiers are not a guarantee for every environment. See django-query-guard on PyPI and its 0.2.1 release page.
As an Amazon Associate I earn from qualifying purchases.
Mark the database-backed test and set a query budget
Apply both markers to a pytest test that exercises the database. Set max_queries to a total query ceiling that makes sense for the operation under test, rather than choosing a number without regard to its expected behavior.
Recommended Free Tools
import pytest
@pytest.mark.django_db
@pytest.mark.query_guard(max_queries=10, detect_n_plus_one=True)
def test_api_lists_articles(client):
response = client.get("/api/articles/")
assert response.status_code == 200
The value 10 is an example budget, not a package default or a universal target. The marker enables total-query counting and repeated normalized-query detection; the documented default for n_plus_one_threshold is 2. Adjust the threshold only when the application’s expected access pattern warrants it. The PyPI documentation also shows using query_guard(...) as a context manager around code such as a view, task, or management command.
#1 Best Overall
Exercise the access pattern that can cause N+1 queries
A test that only constructs a queryset may not trigger the relation lookups responsible for an N+1 problem. Exercise the operation users actually rely on: request the endpoint, render the view, or iterate through results and access related fields the template or serializer needs.
For example, if the API response includes each article’s author, make the test request that response and assert the author data is present. That helps ensure the test reaches the code path that reads the relation, rather than merely checking that the initial queryset can be created.
Rank #2
Fix repeated relation lookups
When the guard reports repeated queries, identify which relation access triggers them and choose the loading method based on the relationship type:
| Relationship | Queryset method | How it helps |
|---|---|---|
| Foreign key or one-to-one | select_related() |
Loads the related object with the original query. |
| Reverse foreign key or many-to-many | prefetch_related() |
Fetches related objects separately and associates them with the original results. |
Apply the appropriate method to the queryset used by the view or other operation, then rerun the test. The guard can catch both a total query count above the budget and repeated normalized queries; fixing the reported relation access should address the source of the excess rather than merely raising the ceiling.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Keep the guard in CI
Commit the regression test and run it as part of the project’s normal pytest suite in continuous integration. That way, later changes to a view, serializer, or template are checked against the query budget and repeated-query detection whenever the test runs.
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




