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()
Metadata
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 | Provenance | Actions |
|---|---|---|---|---|
| django_assert_model_queries-1.1.0.tar.gz | 21.9 kB | Without provenance | Details for django_assert_model_queries-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_assert_model_queries-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for django_assert_model_queries-1.1.0-py3-none-any.whl |
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
|
Security for django-assert-model-queries 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.