From 773dc2dc081ab9f5c103862206b3599931151b30 Mon Sep 17 00:00:00 2001 From: Remigio Furini Date: Tue, 15 Jul 2025 21:07:59 +0200 Subject: [PATCH 1/5] feat: add autodiscover register model for historical tracking --- docs/historical_model.rst | 20 ++++++++++++++++++++ simple_history/__init__.py | 3 +++ simple_history/apps.py | 10 ++++++++++ simple_history/utils.py | 21 +++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 simple_history/apps.py diff --git a/docs/historical_model.rst b/docs/historical_model.rst index 32447f185..3cb442b97 100644 --- a/docs/historical_model.rst +++ b/docs/historical_model.rst @@ -566,3 +566,23 @@ You will see the many to many changes when diffing between two historical record # Output: # categories changed from [{'poll': 1, 'category': 1}, { 'poll': 1, 'category': 2}] to [{'poll': 1, 'category': 2}] + +Organizing history registrations with `historical.py` +----------------------------------- +To keep your project clean and maintainable, place all your `register()` calls +inside a dedicated `historical.py` file within each app. + +With the autodiscover feature, `simple_history` automatically imports these +modules at Django startup, so you don’t need to manually import or register +your historical models elsewhere. + +.. code-block:: python + + # myapp/historical.py + + from simple_history import register + from .models import Product + + + # Register models to track their history + register(Product, inherit=True) diff --git a/simple_history/__init__.py b/simple_history/__init__.py index 1f264718b..87b376491 100644 --- a/simple_history/__init__.py +++ b/simple_history/__init__.py @@ -37,3 +37,6 @@ def register( records.cls = model records.add_extra_methods(model) records.finalize(model) + + +default_app_config = 'simple_history.apps.SimpleHistoryConfig' diff --git a/simple_history/apps.py b/simple_history/apps.py new file mode 100644 index 000000000..d83d97c03 --- /dev/null +++ b/simple_history/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig + + +class SimpleHistoryConfig(AppConfig): + name = 'simple_history' + verbose_name = 'Simple History' + + def ready(self): + from simple_history.utils import autodiscover_history_modules + autodiscover_history_modules() diff --git a/simple_history/utils.py b/simple_history/utils.py index 0fdfc6292..80ddd5b1f 100644 --- a/simple_history/utils.py +++ b/simple_history/utils.py @@ -241,3 +241,24 @@ def get_change_reason_from_object(obj): return getattr(obj, "_change_reason") return None + + +def autodiscover_history_modules(): + """ + Auto-import `.historical` modules and fail silently if not present. + This triggers simple_history.register(...) calls inside those modules. + Typically called at app startup. + """ + from django.apps import apps + from django.utils.module_loading import import_module + from django.utils.module_loading import module_has_submodule + + for app_config in apps.get_app_configs(): + module = f"{app_config.name}.historical" + try: + import_module(module) + except ImportError: + if module_has_submodule(app_config.module, "historical"): + raise + except Exception: + raise From ccce801073c63f8296dd63498697266138be46aa Mon Sep 17 00:00:00 2001 From: Remigio Furini Date: Tue, 15 Jul 2025 21:16:04 +0200 Subject: [PATCH 2/5] feat: add authors and changes rst --- AUTHORS.rst | 1 + CHANGES.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 16602a252..76952a34d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -147,6 +147,7 @@ Authors - `Sridhar Marella `_ - `Mattia Fantoni `_ - `Trent Holliday `_ +- `Remigio Furini `_ Background ========== diff --git a/CHANGES.rst b/CHANGES.rst index 59e00f55b..05e0be91a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,11 @@ Changes Unreleased ---------- +3.10.2 (2025-07-15) +------------------- + +- Add autodiscover mechanism to automatically register historical models from a single centralized location + 3.10.1 (2025-06-20) ------------------- From c82572a3f2221bba9a95d6ffe8026db16badd3b4 Mon Sep 17 00:00:00 2001 From: Remigio Furini Date: Tue, 15 Jul 2025 21:25:30 +0200 Subject: [PATCH 3/5] feat: run pre-commit --- simple_history/__init__.py | 2 +- simple_history/apps.py | 5 +++-- simple_history/utils.py | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/simple_history/__init__.py b/simple_history/__init__.py index 87b376491..0040d682d 100644 --- a/simple_history/__init__.py +++ b/simple_history/__init__.py @@ -39,4 +39,4 @@ def register( records.finalize(model) -default_app_config = 'simple_history.apps.SimpleHistoryConfig' +default_app_config = "simple_history.apps.SimpleHistoryConfig" diff --git a/simple_history/apps.py b/simple_history/apps.py index d83d97c03..2894d12f1 100644 --- a/simple_history/apps.py +++ b/simple_history/apps.py @@ -2,9 +2,10 @@ class SimpleHistoryConfig(AppConfig): - name = 'simple_history' - verbose_name = 'Simple History' + name = "simple_history" + verbose_name = "Simple History" def ready(self): from simple_history.utils import autodiscover_history_modules + autodiscover_history_modules() diff --git a/simple_history/utils.py b/simple_history/utils.py index 80ddd5b1f..383101719 100644 --- a/simple_history/utils.py +++ b/simple_history/utils.py @@ -250,8 +250,7 @@ def autodiscover_history_modules(): Typically called at app startup. """ from django.apps import apps - from django.utils.module_loading import import_module - from django.utils.module_loading import module_has_submodule + from django.utils.module_loading import import_module, module_has_submodule for app_config in apps.get_app_configs(): module = f"{app_config.name}.historical" From 83dd0ec32d9a548536fbf87df566e40078387eb5 Mon Sep 17 00:00:00 2001 From: Remigio Furini Date: Tue, 15 Jul 2025 21:26:45 +0200 Subject: [PATCH 4/5] feat: add pr in changes.rst --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 05e0be91a..418ed7e80 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,7 +7,7 @@ Unreleased 3.10.2 (2025-07-15) ------------------- -- Add autodiscover mechanism to automatically register historical models from a single centralized location +- Add autodiscover mechanism to automatically register historical models from a single centralized location (gh-1504) 3.10.1 (2025-06-20) ------------------- From 71c200d08bf3d2966f5e4b84425cdc94da96319c Mon Sep 17 00:00:00 2001 From: Remigio Furini Date: Wed, 16 Jul 2025 01:14:39 +0200 Subject: [PATCH 5/5] feat: handle missing historical modules silently during autodiscovery --- CHANGES.rst | 2 +- simple_history/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 418ed7e80..d1c433e95 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,7 +7,7 @@ Unreleased 3.10.2 (2025-07-15) ------------------- -- Add autodiscover mechanism to automatically register historical models from a single centralized location (gh-1504) +- Add autodiscovery mechanism to auto-register models in historical.py (gh-1504) 3.10.1 (2025-06-20) ------------------- diff --git a/simple_history/utils.py b/simple_history/utils.py index 383101719..2e9f76402 100644 --- a/simple_history/utils.py +++ b/simple_history/utils.py @@ -257,7 +257,7 @@ def autodiscover_history_modules(): try: import_module(module) except ImportError: + # Only re-raise if the module exists but failed to import + # Silently ignore if the module doesn't exist, as expected if module_has_submodule(app_config.module, "historical"): raise - except Exception: - raise