From 55bda704a445b0f7ebca714cc0c1dab8322f9c8c Mon Sep 17 00:00:00 2001 From: Yuekui Li Date: Wed, 2 Nov 2022 16:45:47 -0700 Subject: [PATCH 1/4] Add pre and post clone save signals --- model_clone/mixin.py | 6 +++- model_clone/signals.py | 4 +++ model_clone/tests/test_clone_signals.py | 38 +++++++++++++++++++++++++ sample/__init__.py | 1 + sample/apps.py | 3 ++ sample/signals.py | 18 ++++++++++++ 6 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 model_clone/signals.py create mode 100644 model_clone/tests/test_clone_signals.py create mode 100644 sample/signals.py diff --git a/model_clone/mixin.py b/model_clone/mixin.py index ddeabe29..69bba149 100644 --- a/model_clone/mixin.py +++ b/model_clone/mixin.py @@ -10,6 +10,7 @@ from django.utils.text import slugify from model_clone.apps import ModelCloneConfig +from model_clone.signals import post_clone_save, pre_clone_save from model_clone.utils import ( clean_value, context_mutable_attribute, @@ -233,13 +234,16 @@ def make_clone(self, attrs=None, sub_clone=False, using=None, parent=None): duplicate = self.pre_save_duplicate(duplicate) duplicate = self.__duplicate_m2o_fields(duplicate, using=using) + + pre_clone_save.send(sender=self.__class__, instance=duplicate) + duplicate.save(using=using) duplicate = self.__duplicate_o2o_fields(duplicate, using=using) duplicate = self.__duplicate_o2m_fields(duplicate, using=using) duplicate = self.__duplicate_m2m_fields(duplicate, using=using) - duplicate.save(using=using) + post_clone_save.send(sender=self.__class__, instance=duplicate) return duplicate diff --git a/model_clone/signals.py b/model_clone/signals.py new file mode 100644 index 00000000..ad5207e1 --- /dev/null +++ b/model_clone/signals.py @@ -0,0 +1,4 @@ +from django.db.models.signals import ModelSignal + +pre_clone_save = ModelSignal(use_caching=True) +post_clone_save = ModelSignal(use_caching=True) diff --git a/model_clone/tests/test_clone_signals.py b/model_clone/tests/test_clone_signals.py new file mode 100644 index 00000000..767a28b5 --- /dev/null +++ b/model_clone/tests/test_clone_signals.py @@ -0,0 +1,38 @@ +from django.contrib.auth import get_user_model +from django.test import TestCase +from django.utils import timezone +from django.utils.text import slugify + +from sample.models import Book, Edition + +User = get_user_model() + + +class CloneSignalsTestCase(TestCase): + REPLICA_DB_ALIAS = "replica" + databases = { + "default", + "replica", + } + + @classmethod + def setUpTestData(cls): + cls.user = User.objects.create(username="user") + + def test_signals(self): + name = "New Book" + first_published_at = timezone.datetime( + 1970, 1, 1, tzinfo=timezone.get_default_timezone() + ) + book = Book.objects.create( + name=name, + created_by=self.user, + slug=slugify(name), + published_at=first_published_at, + ) + assert book.published_at == first_published_at + edition = Edition.objects.create(seq=1, book=book) + cloned_edition = edition.make_clone() + assert cloned_edition.seq == 2 + book.refresh_from_db() + assert book.published_at != first_published_at diff --git a/sample/__init__.py b/sample/__init__.py index e69de29b..248dcd41 100644 --- a/sample/__init__.py +++ b/sample/__init__.py @@ -0,0 +1 @@ +default_app_config = "sample.apps.SampleConfig" diff --git a/sample/apps.py b/sample/apps.py index 5213a8db..5922253f 100644 --- a/sample/apps.py +++ b/sample/apps.py @@ -4,3 +4,6 @@ class SampleConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "sample" + + def ready(self): + from . import signals diff --git a/sample/signals.py b/sample/signals.py new file mode 100644 index 00000000..a216e906 --- /dev/null +++ b/sample/signals.py @@ -0,0 +1,18 @@ +from django.dispatch import receiver +from django.utils import timezone + +from model_clone.signals import post_clone_save, pre_clone_save + +from .models import Edition + + +@receiver(pre_clone_save, sender=Edition) +def increase_seq(sender, instance, **kwargs): + instance.seq += 1 + + +@receiver(post_clone_save, sender=Edition) +def update_book_published_at(sender, instance, **kwargs): + if instance.book: + instance.book.published_at = timezone.now() + instance.book.save(update_fields=["published_at"]) From 29677e936a635696ea478c8683adfb2e6e26ea6b Mon Sep 17 00:00:00 2001 From: Yuekui Li Date: Wed, 2 Nov 2022 17:06:53 -0700 Subject: [PATCH 2/4] Fix auto commit --- sample/apps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sample/apps.py b/sample/apps.py index 5922253f..7aa8007b 100644 --- a/sample/apps.py +++ b/sample/apps.py @@ -1,3 +1,4 @@ +# pylint: disable=unused-import from django.apps import AppConfig @@ -6,4 +7,4 @@ class SampleConfig(AppConfig): name = "sample" def ready(self): - from . import signals + from . import signals # noqa: F401 From c84b19d32fbce7c9280261b7dd4138e31fef6a1d Mon Sep 17 00:00:00 2001 From: Yuekui Li Date: Wed, 2 Nov 2022 17:10:37 -0700 Subject: [PATCH 3/4] Fix assert annotations --- model_clone/tests/test_clone_signals.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/model_clone/tests/test_clone_signals.py b/model_clone/tests/test_clone_signals.py index 767a28b5..2d6e7be6 100644 --- a/model_clone/tests/test_clone_signals.py +++ b/model_clone/tests/test_clone_signals.py @@ -30,9 +30,9 @@ def test_signals(self): slug=slugify(name), published_at=first_published_at, ) - assert book.published_at == first_published_at + self.assertEqual(book.published_at, first_published_at) edition = Edition.objects.create(seq=1, book=book) cloned_edition = edition.make_clone() - assert cloned_edition.seq == 2 + self.assertEqual(cloned_edition.seq, 2) book.refresh_from_db() - assert book.published_at != first_published_at + self.assertNotEqual(book.published_at, first_published_at) From 976311c3cdd0c5b144fcdcb451388992287baf4e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Nov 2022 00:11:11 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- sample/apps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/apps.py b/sample/apps.py index 7aa8007b..cdcad2e7 100644 --- a/sample/apps.py +++ b/sample/apps.py @@ -7,4 +7,4 @@ class SampleConfig(AppConfig): name = "sample" def ready(self): - from . import signals # noqa: F401 + from . import signals # noqa: F401