django-sql-test
Prevent SQL regressions, detect N+1 queries, and visualize query diffs in your Django tests. A test mixin that captures, snapshots, and diffs all executed SQL queries in your test output.
$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Queries diff:
- SELECT polls_choice.id FROM polls_choice
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
SELECT COUNT(*) AS __count FROM polls_question
Table of Contents
Requirements
- Django >= 4.0
- Python >= 3.9
Installation
pip install django-sql-test
Quickstart
In your test.py just import NumNewQueriesMixin and add it as a parent:
from django.test import TestCase
from django_sql_test import NumNewQueriesMixin
class FooTest(NumNewQueriesMixin, TestCase):
def test_bar(self):
with self.assertNumNewQueries(2):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
What you got before adding NumNewQueriesMixin:
$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Captured queries were:
1. SELECT "polls_choice"."id" FROM "polls_choice" WHERE "polls_choice"."votes" >= 0
2. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
3. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
4. SELECT "polls_question"."id" FROM "polls_question" WHERE "polls_question"."id" = 1 LIMIT 21
5. SELECT COUNT(*) AS "__count" FROM "polls_question"
What you get after adding NumNewQueriesMixin:
$ poetry run python manage.py test path.to.test.FooTest.test_bar
======================================================================
FAIL: test_bar (path.to.test.FooTest.test_bar)
...
AssertionError: 5 != 2 : 5 queries executed, 2 expected
Queries diff:
- SELECT polls_choice.id FROM polls_choice
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
+ SELECT polls_question.id FROM polls_question WHERE polls_question.id = N LIMIT N
SELECT COUNT(*) AS __count FROM polls_question
Configuration
Configure via your Django settings:
| Setting | Default | Description |
|---|---|---|
SQL_TEST_GENERALIZED_DIFF |
True |
Hides SQL query parameters by replacing them with placeholders. |
SQL_TEST_DIFF_ONLY |
False |
If set to True, shows only SQL queries that were added or removed; otherwise, shows all queries. |
SQL_TEST_DIFF_NEW_COLOR |
"\033[1;32m" |
Color code for newly added SQL queries (green). |
SQL_TEST_DIFF_OLD_COLOR |
"\033[1;31m" |
Color code for removed SQL queries (red). |
SQL_TEST_DIFF_DEFAULT_COLOR |
"\033[0m" |
Base console color code for unchanged SQL queries. |
SQL_TEST_ENGINE |
"file" |
Engine used to store the last successful SQL queries. Default "file" engine stores data in the file from SQL_TEST_ENGINE_SETTINGS["filename"], or in .django_sql_test_queries at the project root if not set. You can implement a custom engine by inheriting from django_sql_test.engine.Engine, overriding its methods, and specifying its full path, e.g., SQL_TEST_ENGINE = "path.to.YourEngine". |
SQL_TEST_ENGINE_SETTINGS |
{} |
Dictionary of settings passed to the engine's constructor. For the default "file" engine, you can pass the path to the file where queries will be stored in JSON format. |
SQL_TEST_GENERALIZED_DIFF
If set to True:
Queries diff:
+ SELECT polls_choice.id FROM polls_choice WHERE polls_choice.votes >= N
If set to False:
Queries diff:
+ SELECT "polls_choice"."id" FROM "polls_choice" WHERE "polls_choice"."votes" >= 0
API Reference
NumNewQueriesMixin
| Method | Description |
|---|---|
assertNumNewQueries |
Works just like django.test.testcases.TransactionTestCase.assertNumQueries, but also prints the diff of queries compared to the last successful run, if any. |
assertNumQueries |
Acts like assertNumNewQueries. It can be used if you don’t want to replace every occurrence of assertNumQueries with assertNumNewQueries in your tests. Simply inherit from it in your test class, for example: class PaginatorsTestCase(NumNewQueriesMixin, ViewTestCase), and everything will work out of the box. |
Contributing
We welcome contributions! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/YourFeature) - Write tests and ensure coverage
- Run and pass:
poetry run isort -c --diff --settings-file pyproject.toml . poetry run black --diff --config pyproject.toml --check . poetry run python runtests.py
- Submit a pull request
License
This project is licensed under the MIT License. See LICENSE for details.
Changelog
All notable changes are documented on the Releases page.
Metadata
Release files for django-sql-test 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_sql_test-0.3.0.tar.gz | 5.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_sql_test-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.9 kB
Release files / django_sql_test-0.3.0.tar.gz
| Download URL | django_sql_test-0.3.0.tar.gz |
|---|---|
| Size | 5.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
28d6dd56870b043ffc57da8cbd6a08a551e09203c5f47d66c6ac1950b7d36c86
|
|
BLAKE2b-256 checksum How to use checksums |
0145a68301650a159a3c7d3d503bd687e2697b78c8dc0ec46b2ea1c4892685f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.1 CPython/3.13.2 Darwin/24.5.0
|
Release files / django_sql_test-0.3.0-py3-none-any.whl
| Download URL | django_sql_test-0.3.0-py3-none-any.whl |
|---|---|
| Size | 7.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1051eea2bc2277a84f9076343b986cf4b22451d4c4e6b2bd8e5e4c2ecd98cbd3
|
|
BLAKE2b-256 checksum How to use checksums |
33fe8b722e9690d6d0a31919e9e414ab39ab89f16a59a44b2af45cb094d1daf8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.1 CPython/3.13.2 Darwin/24.5.0
|