From 3a5103c8866e7fb9c45c5d9c0c9fe500b188855d Mon Sep 17 00:00:00 2001 From: The-Alchemist Date: Fri, 6 Jun 2025 13:02:13 -0400 Subject: [PATCH 1/2] support for --default-date for populate_history command --- runtests.py | 8 ++++---- .../management/commands/populate_history.py | 20 +++++++++++++------ simple_history/tests/tests/test_commands.py | 10 ++++++++++ simple_history/tests/tests/test_utils.py | 17 ++++++++++++++++ 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/runtests.py b/runtests.py index de2e9c194..4e8069d2e 100755 --- a/runtests.py +++ b/runtests.py @@ -46,16 +46,16 @@ def __getitem__(self, item): "default": { "ENGINE": "django.db.backends.postgresql", "NAME": "test", - "USER": "postgres", - "PASSWORD": "postgres", + "USER": "debug", + "PASSWORD": "debug", "HOST": "127.0.0.1", "PORT": 5432, }, "other": { "ENGINE": "django.db.backends.postgresql", "NAME": "other", - "USER": "postgres", - "PASSWORD": "postgres", + "USER": "debug", + "PASSWORD": "debug", "HOST": "127.0.0.1", "PORT": 5432, }, diff --git a/simple_history/management/commands/populate_history.py b/simple_history/management/commands/populate_history.py index b078f5526..81d2cd0e7 100644 --- a/simple_history/management/commands/populate_history.py +++ b/simple_history/management/commands/populate_history.py @@ -42,6 +42,13 @@ def add_arguments(self, parser): type=int, help="Set a custom batch size when bulk inserting historical records.", ) + parser.add_argument( + "--default-date", + action="store", + dest="default_date", + default=None, + help="Set a custom date for the historical records.", + ) def handle(self, *args, **options): self.verbosity = options["verbosity"] @@ -60,7 +67,7 @@ def handle(self, *args, **options): if self.verbosity >= 1: self.stdout.write(self.COMMAND_HINT) - self._process(to_process, batch_size=options["batchsize"]) + self._process(to_process, batch_size=options["batchsize"], default_date=options["default_date"]) def _auto_models(self): to_process = set() @@ -109,11 +116,12 @@ def _model_from_natural_key(self, natural_key): raise ValueError(msg) return model, history_model - def _bulk_history_create(self, model, batch_size): + def _bulk_history_create(self, model, batch_size, default_date=None): """Save a copy of all instances to the historical model. :param model: Model you want to bulk create :param batch_size: number of models to create at once. + :param default_date: date to set for the historical records. :return: """ @@ -135,7 +143,7 @@ def _bulk_history_create(self, model, batch_size): # creating them. So we only keep batch_size worth of models in # historical_instances and clear them after we hit batch_size if index % batch_size == 0: - history.bulk_history_create(instances, batch_size=batch_size) + history.bulk_history_create(instances, batch_size=batch_size, default_date=default_date) instances = [] @@ -151,9 +159,9 @@ def _bulk_history_create(self, model, batch_size): # create any we didn't get in the last loop if instances: - history.bulk_history_create(instances, batch_size=batch_size) + history.bulk_history_create(instances, batch_size=batch_size, default_date=default_date) - def _process(self, to_process, batch_size): + def _process(self, to_process, batch_size, default_date=None): for model, history_model in to_process: if history_model.objects.exists(): self.stderr.write( @@ -164,6 +172,6 @@ def _process(self, to_process, batch_size): continue if self.verbosity >= 1: self.stdout.write(self.START_SAVING_FOR_MODEL.format(model=model)) - self._bulk_history_create(model, batch_size) + self._bulk_history_create(model, batch_size, default_date) if self.verbosity >= 1: self.stdout.write(self.DONE_SAVING_FOR_MODEL.format(model=model)) diff --git a/simple_history/tests/tests/test_commands.py b/simple_history/tests/tests/test_commands.py index f2f166580..20c1443bc 100644 --- a/simple_history/tests/tests/test_commands.py +++ b/simple_history/tests/tests/test_commands.py @@ -194,6 +194,16 @@ def test_excluded_fields(self): initial_history_record = PollWithExcludeFields.history.all()[0] self.assertEqual(initial_history_record.question, poll.question) + def test_populate_with_default_date(self): + date = datetime(2020, 7, 1) + Poll.objects.create(question="Will this populate?", pub_date=datetime.now()) + Poll.history.all().delete() + management.call_command( + self.command_name, auto=True, default_date=date, stdout=StringIO(), stderr=StringIO() + ) + self.assertEqual(Poll.history.all().count(), 1) + self.assertEqual(Poll.history.all()[0].history_date, date) + class TestCleanDuplicateHistory(TestCase): command_name = "clean_duplicate_history" diff --git a/simple_history/tests/tests/test_utils.py b/simple_history/tests/tests/test_utils.py index 7db701d98..50e2d221a 100644 --- a/simple_history/tests/tests/test_utils.py +++ b/simple_history/tests/tests/test_utils.py @@ -630,6 +630,22 @@ def test_bulk_manager_with_custom_model_attributes(self): 5, ) + def test_bulk_history_create_with_default_date(self): + date = datetime(2020, 7, 1) + history_manager = get_history_manager_for_model(PollWithHistoricalSessionAttr) + history_manager.bulk_history_create(self.data, default_date=date) + + self.assertEqual(PollWithHistoricalSessionAttr.objects.count(), 0) + self.assertEqual(PollWithHistoricalSessionAttr.history.count(), 5) + self.assertTrue( + all( + [ + history.history_date == date + for history in PollWithHistoricalSessionAttr.history.all() + ] + ) + ) + class UpdateChangeReasonTestCase(TestCase): def test_update_change_reason_with_excluded_fields(self): @@ -640,3 +656,4 @@ def test_update_change_reason_with_excluded_fields(self): update_change_reason(poll, "Test change reason.") most_recent = poll.history.order_by("-history_date").first() self.assertEqual(most_recent.history_change_reason, "Test change reason.") + From b07b29ae0182bcaa388d95d07e0ac1998b67985c Mon Sep 17 00:00:00 2001 From: The-Alchemist Date: Fri, 6 Jun 2025 13:08:38 -0400 Subject: [PATCH 2/2] populate_history: support for default-date parameter --- CHANGES.rst | 1 + runtests.py | 8 ++++---- .../management/commands/populate_history.py | 14 +++++++++++--- simple_history/tests/tests/test_commands.py | 6 +++++- simple_history/tests/tests/test_utils.py | 1 - 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 45eee1b1e..5fe944ae3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,7 @@ Unreleased ---------- - Tests are no longer bundled in released wheels (gh-1478) +- Added ``--default-date`` option to ``populate_history`` command (gh-688) 3.9.0 (2025-01-26) ------------------ diff --git a/runtests.py b/runtests.py index 4e8069d2e..de2e9c194 100755 --- a/runtests.py +++ b/runtests.py @@ -46,16 +46,16 @@ def __getitem__(self, item): "default": { "ENGINE": "django.db.backends.postgresql", "NAME": "test", - "USER": "debug", - "PASSWORD": "debug", + "USER": "postgres", + "PASSWORD": "postgres", "HOST": "127.0.0.1", "PORT": 5432, }, "other": { "ENGINE": "django.db.backends.postgresql", "NAME": "other", - "USER": "debug", - "PASSWORD": "debug", + "USER": "postgres", + "PASSWORD": "postgres", "HOST": "127.0.0.1", "PORT": 5432, }, diff --git a/simple_history/management/commands/populate_history.py b/simple_history/management/commands/populate_history.py index 81d2cd0e7..ee32d16d4 100644 --- a/simple_history/management/commands/populate_history.py +++ b/simple_history/management/commands/populate_history.py @@ -67,7 +67,11 @@ def handle(self, *args, **options): if self.verbosity >= 1: self.stdout.write(self.COMMAND_HINT) - self._process(to_process, batch_size=options["batchsize"], default_date=options["default_date"]) + self._process( + to_process, + batch_size=options["batchsize"], + default_date=options["default_date"], + ) def _auto_models(self): to_process = set() @@ -143,7 +147,9 @@ def _bulk_history_create(self, model, batch_size, default_date=None): # creating them. So we only keep batch_size worth of models in # historical_instances and clear them after we hit batch_size if index % batch_size == 0: - history.bulk_history_create(instances, batch_size=batch_size, default_date=default_date) + history.bulk_history_create( + instances, batch_size=batch_size, default_date=default_date + ) instances = [] @@ -159,7 +165,9 @@ def _bulk_history_create(self, model, batch_size, default_date=None): # create any we didn't get in the last loop if instances: - history.bulk_history_create(instances, batch_size=batch_size, default_date=default_date) + history.bulk_history_create( + instances, batch_size=batch_size, default_date=default_date + ) def _process(self, to_process, batch_size, default_date=None): for model, history_model in to_process: diff --git a/simple_history/tests/tests/test_commands.py b/simple_history/tests/tests/test_commands.py index 20c1443bc..e1652f74d 100644 --- a/simple_history/tests/tests/test_commands.py +++ b/simple_history/tests/tests/test_commands.py @@ -199,7 +199,11 @@ def test_populate_with_default_date(self): Poll.objects.create(question="Will this populate?", pub_date=datetime.now()) Poll.history.all().delete() management.call_command( - self.command_name, auto=True, default_date=date, stdout=StringIO(), stderr=StringIO() + self.command_name, + auto=True, + default_date=date, + stdout=StringIO(), + stderr=StringIO(), ) self.assertEqual(Poll.history.all().count(), 1) self.assertEqual(Poll.history.all()[0].history_date, date) diff --git a/simple_history/tests/tests/test_utils.py b/simple_history/tests/tests/test_utils.py index 50e2d221a..ebd9c9f30 100644 --- a/simple_history/tests/tests/test_utils.py +++ b/simple_history/tests/tests/test_utils.py @@ -656,4 +656,3 @@ def test_update_change_reason_with_excluded_fields(self): update_change_reason(poll, "Test change reason.") most_recent = poll.history.order_by("-history_date").first() self.assertEqual(most_recent.history_change_reason, "Test change reason.") -