From 70e089fec1fcdccbe025222dc23963ed55ea4c95 Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Sat, 25 Oct 2025 09:08:46 -0500 Subject: [PATCH 1/3] Hide the migrations when not using the database store. This is a bit of a hack as we're adjusting the project's settings and it hides all migrations. --- debug_toolbar/apps.py | 16 ++++++++++++++++ docs/changes.rst | 2 ++ docs/configuration.rst | 8 ++++---- tests/test_apps.py | 27 +++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 tests/test_apps.py diff --git a/debug_toolbar/apps.py b/debug_toolbar/apps.py index a49875bac..848fc6f77 100644 --- a/debug_toolbar/apps.py +++ b/debug_toolbar/apps.py @@ -24,6 +24,22 @@ def ready(self): # allows panels like CachePanel to enable their instrumentation immediately. for cls in DebugToolbar.get_panel_classes(): cls.ready() + _manage_migrations_visibility(self.name) + + +def _manage_migrations_visibility(app_name): + """ + Adjust the toolbar's migration visibility by manipulating the + project's settings. + + This is a hack since it's manipulating settings. + """ + if ( + dt_settings.get_config()["TOOLBAR_STORE_CLASS"] + != "debug_toolbar.store.DatabaseStore" + ): + # This effectively hides the migrations by telling Django they don't exist. + settings.MIGRATION_MODULES.setdefault(app_name, None) def check_template_config(config): diff --git a/docs/changes.rst b/docs/changes.rst index 13456a4ef..627430b59 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -16,6 +16,8 @@ Pending * Upgraded CI ``postgis`` version to 17-3.5. * Added how to generate the documentation locally to the contributing documentation. +* Hide the toolbar's migrations unless the database store is being used. This + may change in the future. * Updated logic that forces values to strings (``force_str``) to render "Django Debug Toolbar was unable to parse value." when there's a decoding error. diff --git a/docs/configuration.rst b/docs/configuration.rst index 46359da83..5c9123e3f 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -196,15 +196,15 @@ Toolbar options The DatabaseStore provides persistence and automatically cleans up old entries based on the ``RESULTS_CACHE_SIZE`` setting. - Note: For full functionality, DatabaseStore requires migrations for - the debug_toolbar app: + Note: When using ``DatabaseStore`` migrations are required for + the ``debug_toolbar`` app: .. code-block:: bash python manage.py migrate debug_toolbar - For the DatabaseStore to work properly, you need to run migrations for the - debug_toolbar app. The migrations create the necessary database table to store + For the ``DatabaseStore`` to work properly, you need to run migrations for the + ``debug_toolbar`` app. The migrations create the necessary database table to store toolbar data. .. _TOOLBAR_LANGUAGE: diff --git a/tests/test_apps.py b/tests/test_apps.py new file mode 100644 index 000000000..37521f0a7 --- /dev/null +++ b/tests/test_apps.py @@ -0,0 +1,27 @@ +from unittest.mock import patch + +from django.test import SimpleTestCase, override_settings + +from debug_toolbar.apps import _manage_migrations_visibility + + +class AppsTestCase(SimpleTestCase): + @override_settings( + DEBUG_TOOLBAR_CONFIG={ + "TOOLBAR_STORE_CLASS": "debug_toolbar.store.DatabaseStore" + } + ) + @patch("debug_toolbar.apps.settings.MIGRATION_MODULES") + def test_migrations_are_visible(self, mocked_migration_modules): + _manage_migrations_visibility("debug_toolbar") + self.assertFalse(mocked_migration_modules.setdefault.called) + + @override_settings( + DEBUG_TOOLBAR_CONFIG={"TOOLBAR_STORE_CLASS": "debug_toolbar.store.MemoryStore"} + ) + @patch("debug_toolbar.apps.settings.MIGRATION_MODULES") + def test_migrations_are_hidden(self, mocked_migration_modules): + _manage_migrations_visibility("debug_toolbar") + mocked_migration_modules.setdefault.assert_called_once_with( + "debug_toolbar", None + ) From 7bbc35536d67a69c0cf8320f791cf17407121c28 Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Sat, 25 Oct 2025 09:21:08 -0500 Subject: [PATCH 2/3] Hide the toolbar's models when the database store isn't used. --- debug_toolbar/apps.py | 13 +++++++++++++ docs/changes.rst | 7 +++++-- tests/test_apps.py | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/debug_toolbar/apps.py b/debug_toolbar/apps.py index 848fc6f77..776c6a810 100644 --- a/debug_toolbar/apps.py +++ b/debug_toolbar/apps.py @@ -26,6 +26,19 @@ def ready(self): cls.ready() _manage_migrations_visibility(self.name) + def import_models(self): + """ + Override import models to avoid allowing users to dynamically fetch a model + that doesn't have a table behind it unless they are using the DatabaseStore. + This also prevents the command `migrate --run-syncdb` from creating tables + for the models. + """ + dt_config = dt_settings.get_config() + if dt_config["TOOLBAR_STORE_CLASS"] == "debug_toolbar.store.DatabaseStore": + return super().import_models() + # Not using the database store, don't import the models + self.models = {} + def _manage_migrations_visibility(app_name): """ diff --git a/docs/changes.rst b/docs/changes.rst index 627430b59..7dfb3b688 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -16,12 +16,15 @@ Pending * Upgraded CI ``postgis`` version to 17-3.5. * Added how to generate the documentation locally to the contributing documentation. -* Hide the toolbar's migrations unless the database store is being used. This - may change in the future. * Updated logic that forces values to strings (``force_str``) to render "Django Debug Toolbar was unable to parse value." when there's a decoding error. * Updated docs to show incompatibility with Django Channels. +* Hide the toolbar's migrations unless ``debug_toolbar.store.DatabaseStore`` + is being used. This may change in the future. +* Hide ``debug_toolbar.HistoryEntry`` as a model unless + ``debug_toolbar.store.DatabaseStore`` is being used. This may change in the + future. 6.0.0 (2025-07-22) ------------------ diff --git a/tests/test_apps.py b/tests/test_apps.py index 37521f0a7..9b6012bed 100644 --- a/tests/test_apps.py +++ b/tests/test_apps.py @@ -1,5 +1,6 @@ from unittest.mock import patch +from django.apps import apps from django.test import SimpleTestCase, override_settings from debug_toolbar.apps import _manage_migrations_visibility @@ -25,3 +26,22 @@ def test_migrations_are_hidden(self, mocked_migration_modules): mocked_migration_modules.setdefault.assert_called_once_with( "debug_toolbar", None ) + + @override_settings( + DEBUG_TOOLBAR_CONFIG={ + "TOOLBAR_STORE_CLASS": "debug_toolbar.store.DatabaseStore" + } + ) + def test_models_are_visible(self): + app_config = apps.get_app_config("debug_toolbar") + app_config.import_models() + apps.get_model("debug_toolbar", "HistoryEntry") + + @override_settings( + DEBUG_TOOLBAR_CONFIG={"TOOLBAR_STORE_CLASS": "debug_toolbar.store.MemoryStore"} + ) + def test_models_are_hidden(self): + app_config = apps.get_app_config("debug_toolbar") + app_config.import_models() + with self.assertRaises(LookupError): + apps.get_model("debug_toolbar", "HistoryEntry") From 0dde199bfb9d92aa037552ab4c414b6a0d6b865f Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Sat, 25 Oct 2025 09:35:36 -0500 Subject: [PATCH 3/3] Force the tests to always find the toolbar's migrations. --- tests/settings.py | 4 ++++ tests/test_store.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/tests/settings.py b/tests/settings.py index e10338cb4..8302b7bc2 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -128,6 +128,10 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField" +# Force the MIGRATION_MODULES to always find our migrations. +# See debug_toolbar/apps.py::_manage_migrations_visibility +MIGRATION_MODULES = {"debug_toolbar": "debug_toolbar.migrations"} + # Debug Toolbar configuration DEBUG_TOOLBAR_CONFIG = { diff --git a/tests/test_store.py b/tests/test_store.py index e2425b4e8..51e614826 100644 --- a/tests/test_store.py +++ b/tests/test_store.py @@ -132,6 +132,9 @@ def test_get_store_with_setting(self): self.assertIs(store.get_store(), StubStore) +@override_settings( + DEBUG_TOOLBAR_CONFIG={"TOOLBAR_STORE_CLASS": "debug_toolbar.store.DatabaseStore"} +) class DatabaseStoreTestCase(TestCase): @classmethod def setUpTestData(cls) -> None: