Django Assert Model Queries
This project seeks to assist asserting the number of queries per model during testing.
Note: This does so by monkey-patching the SQLCompiler classes. It's
not something that should be relied upon in production.
Installation
pip install django-assert-model-queries
Usage
There are integrations for both pytest and Django / unittest. Both of
which use the context manager,
django_assert_model_queries.AssertModelQueries under the
hood.
The basic usage is to define a dictionary of expected queries to be evaluated at the end of the context manager's scope. If the counts differ, a helpful error message will be rendered indicating what the differences were and what all the queries were during the context.
from django_assert_model_queries import AssertModelQueries
from testapp.models import Community
with AssertModelQueries({"testapp.Community": 2}):
Community.objects.create(name="test")
Community.objects.update(name="test")
When an unexpected query runs, this AssertModelQueries will
tell you which model generated an unexpected query.
Example error
Here is an example of what you can expect from the tool:
>>> from django_assert_model_queries import AssertModelQueries
>>> from django.contrib.auth.models import User
>>> with AssertModelQueries({}):
>>> User.objects.first()
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[1], line 3
1 from django_assert_model_queries import AssertModelQueries
2 from django.contrib.auth.models import User
----> 3 with AssertModelQueries({}):
4 User.objects.only("id").first()
File ~/site-packages/django_assert_model_queries/test.py:145, in AssertModelQueries.__exit__(self, exc_type, exc_value, traceback)
142 if exc_type is not None:
143 return
--> 145 self.handle_assertion(actual, expected)
146 self.expected_model_counts = None
File ~/site-packages/django_assert_model_queries/test.py:172, in AssertModelQueries.handle_assertion(self, actual, expected)
170 pytest.fail(self.failure_message(actual, expected))
171 else:
--> 172 assert actual == expected, self.failure_message(actual, expected)
AssertionError: {'auth.User': 1} != {}
- {'auth.User': 1}
+ {}
All queries:
SELECT "auth_user"."id" FROM "auth_user" ORDER BY "auth_user"."id" ASC LIMIT 1
Integrating with pytest
If you use pytest, you can use the fixture assert_model_queries as a short-cut.
# pytest example
import pytest
from testapp.models import Community
class TestPytestIntegration:
@pytest.mark.django_db
def test_assert_model_queries(self, assert_model_queries):
with assert_model_queries({"testapp.Community": 1}):
Community.objects.create(name="test")
with assert_model_queries({
"testapp.Community": 2,
"testapp.Chapter": 1,
"testapp.Community_topics": 1,
}):
Community.objects.all().delete()
Integrating with unittest
If you test with Django's TestCase, inherit from the mixin
ModelNumQueriesHelper to be able to utilize the
self.assertModelQueries assertion method.
# Django TestCase example
from django.test import TestCase
from django_assert_model_queries import AssertModelQueries, ModelNumQueriesHelper
from testapp.models import Community
class TestDjangoIntegration(ModelNumQueriesHelper, TestCase):
def test_assert_model_num_queries_context(self):
with AssertModelQueries({"testapp.Community": 1}):
Community.objects.create(name="test")
with AssertModelQueries({"testapp.Community": 2, "testapp.Chapter": 1, "testapp.Community_topics": 1}):
Community.objects.all().delete()
class TestDjangoHelperIntegration(ModelNumQueriesHelper, TestCase):
def test_helper(self):
with self.assertModelQueries({"testapp.Community": 1}):
Community.objects.create(name="test")
with self.assertModelQueries({"testapp.Community": 2, "testapp.Chapter": 1, "testapp.Community_topics": 1}):
Community.objects.all().delete()
Complex usages
There are a few parameters that may help in certain scenarios.
ignore: A collection of models that should be ignored. For example, maybe you want to ignoreSessionqueries if you're using a database backed session.strict=False: You can limit the count evaluation to just the models specified in theexpect_model_countscollection. Be warned, this can hide N+1 issues.
To use these, you must specify them when instantiating
AssertModelQueries.
from django_assert_model_queries import AssertModelQueries
from django.contrib.sessions.models import Session
assert_context = AssertModelQueries(ignore={Session})
with assert_context({"testapp.Community": 1}):
do_something()
assert_context = AssertModelQueries(strict=False)
with assert_context({"testapp.Community": 1}):
do_something()
Release files for django-assert-model-queries 1.1.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_assert_model_queries-1.1.0.tar.gz | 21.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_assert_model_queries-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.9 kB
Release files / django_assert_model_queries-1.1.0.tar.gz
| Download URL | django_assert_model_queries-1.1.0.tar.gz |
|---|---|
| Size | 21.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e9d77f03fcc6adc12175bd2b9b59bd43f2990547f4e68e53b3a647a1b5e9d935
|
|
BLAKE2b-256 checksum How to use checksums |
ad97d493a1899a5b6087f4e8c97cbc90dcb379fa6c85ea0768da5bbf9862538e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/5.1.1 CPython/3.12.7
|
Release files / django_assert_model_queries-1.1.0-py3-none-any.whl
| Download URL | django_assert_model_queries-1.1.0-py3-none-any.whl |
|---|---|
| Size | 8.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e09cd62780b0e808fa933200fb7cc699b9d5061cd16dba6ce666559243b7581b
|
|
BLAKE2b-256 checksum How to use checksums |
626b7b24b27182aff46a36e3469388fee09fd664b909358e2736e86b82160638
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/5.1.1 CPython/3.12.7
|