diff --git a/AUTHORS.rst b/AUTHORS.rst index 16602a25..76952a34 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 59e00f55..d1c433e9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,11 @@ Changes Unreleased ---------- +3.10.2 (2025-07-15) +------------------- + +- Add autodiscovery mechanism to auto-register models in historical.py (gh-1504) + 3.10.1 (2025-06-20) ------------------- diff --git a/docs/historical_model.rst b/docs/historical_model.rst index 32447f18..3cb442b9 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 1f264718..0040d682 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 00000000..2894d12f --- /dev/null +++ b/simple_history/apps.py @@ -0,0 +1,11 @@ +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 0fdfc629..2e9f7640 100644 --- a/simple_history/utils.py +++ b/simple_history/utils.py @@ -241,3 +241,23 @@ 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, module_has_submodule + + for app_config in apps.get_app_configs(): + module = f"{app_config.name}.historical" + 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