From 461ed6da12db82b26c16e9c00035cc508ba04046 Mon Sep 17 00:00:00 2001 From: partizaans Date: Sun, 12 May 2024 12:38:52 +0330 Subject: [PATCH] fix: Update the initial state after calling `refresh_from_db` on the model instance --- django_lifecycle/mixins.py | 4 ++++ docs/advanced.md | 8 ++++---- tests/testapp/tests/test_mixin.py | 11 +++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/django_lifecycle/mixins.py b/django_lifecycle/mixins.py index c68252d..165a818 100644 --- a/django_lifecycle/mixins.py +++ b/django_lifecycle/mixins.py @@ -212,6 +212,10 @@ def delete(self, *args, **kwargs): self._run_hooked_methods(AFTER_DELETE, **kwargs) return value + def refresh_from_db(self, *args, **kwargs): + super().refresh_from_db(*args, **kwargs) + self._initial_state = self._snapshot_state() + @classmethod @lru_cache(typed=True) def _potentially_hooked_methods(cls): diff --git a/docs/advanced.md b/docs/advanced.md index f0c4715..eede003 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -4,10 +4,10 @@ These are available on your model instance when the mixin or extend the base model is used. -| Method | Details | -|:----------------------------------------:|:-------------------------------------------------------------------------------------------------:| -| `has_changed(field_name: str) -> bool` | Return a boolean indicating whether the field's value has changed since the model was initialized | -| `initial_value(field_name: str) -> bool` | Return the value of the field when the model was first initialized | +| Method | Details | +|:----------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------:| +| `has_changed(field_name: str) -> bool` | Return a boolean indicating whether the field's value has changed since the model was initialized, or refreshed from db | +| `initial_value(field_name: str) -> bool` | Return the value of the field when the model was first initialized, or refreshed from db | ### Example You can use these methods for more advanced checks, for example: diff --git a/tests/testapp/tests/test_mixin.py b/tests/testapp/tests/test_mixin.py index 0c90d8f..6bb4c9c 100644 --- a/tests/testapp/tests/test_mixin.py +++ b/tests/testapp/tests/test_mixin.py @@ -203,6 +203,17 @@ def test_has_changed(self): user_account.username = "Josephine" self.assertTrue(user_account.has_changed("username")) + def test_has_changed_when_refreshed_from_db(self): + data = self.stub_data + UserAccount.objects.create(**data) + user_account = UserAccount.objects.get() + UserAccount.objects.update(username="not " + user_account.username) + user_account.refresh_from_db() + user_account.username = data["username"] + self.assertTrue(user_account.has_changed("username"), + 'The initial state should get updated after refreshing the object from db') + + def test_has_changed_is_true_if_fk_related_model_field_has_changed(self): org = Organization.objects.create(name="Dunder Mifflin") UserAccount.objects.create(**self.stub_data, organization=org)