Skip to main content

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 ignore Session queries if you're using a database backed session.
  • strict=False: You can limit the count evaluation to just the models specified in the expect_model_counts collection. 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)

Source distribution for django-assert-model-queries 1.1.0
File Size Uploaded
django_assert_model_queries-1.1.0.tar.gz 21.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-assert-model-queries 1.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page