diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d08703..7a4c4d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. +## 0.0.7 (2023-07-06) +- A fix where `send_post_create_signal()` was being called twice when creating an object through `BulkTrackerQuerySet.create()` + ## 0.0.6 (2023-05-28) - Inheriting from BulkTrackerQuerySet is no longer mandatory. - If you don't have a custom Manager/QuerySet, You can just make your model inherit BulkTrackerModel. diff --git a/bulk_tracker/__init__.py b/bulk_tracker/__init__.py index 034f46c..6526deb 100644 --- a/bulk_tracker/__init__.py +++ b/bulk_tracker/__init__.py @@ -1 +1 @@ -__version__ = "0.0.6" +__version__ = "0.0.7" diff --git a/bulk_tracker/managers.py b/bulk_tracker/managers.py index dbd8e6f..eec3ce2 100644 --- a/bulk_tracker/managers.py +++ b/bulk_tracker/managers.py @@ -53,8 +53,9 @@ def create(self, *, tracking_info_: TrackingInfo | None = None, **kwargs): Create a new object with the given kwargs, saving it to the database and returning the created object. """ + + # NOTE: send_post_create_signal is called after 'create' gets executed, where model.save is called obj = super().create(**kwargs) - send_post_create_signal([obj], model=self.model, tracking_info_=tracking_info_) return obj # This function is just copied from django core, with minor modification to accept TrackingInfo diff --git a/tests/test_create_signal.py b/tests/test_create_signal.py index 3d36c5a..2a44ef9 100644 --- a/tests/test_create_signal.py +++ b/tests/test_create_signal.py @@ -1,5 +1,7 @@ from __future__ import annotations +from unittest.mock import patch + from django.test import TestCase from bulk_tracker.helper_objects import ModifiedObject, TrackingInfo @@ -109,3 +111,74 @@ def post_create_receiver( self.assertEqual("1998-01-08", modified_objects[0].instance.publish_date) self.assertEqual(self.author_john, modified_objects[0].instance.author) self.assertEqual({}, modified_objects[0].changed_values) + + @patch('bulk_tracker.signals.post_create_signal.send') + def test_model_save_should_only_emit_post_create_signal_once(self, mocked_signal): + # Arrange + signal_called_with = {} + + def post_create_receiver( + sender, + objects: list[ModifiedObject[Post]], + tracking_info_: TrackingInfo | None = None, + **kwargs, + ): + signal_called_with["objects"] = objects + signal_called_with["tracking_info_"] = tracking_info_ + + post_create_signal.connect(post_create_receiver, sender=Post) + + # Act + Post(title="Sound of Winter", publish_date="1998-01-08", author=self.author_john).save() + + # Assert + self.assertEqual(mocked_signal.call_count, 1, msg="The signal wasn't called once") + + @patch('bulk_tracker.signals.post_create_signal.send') + def test_model_create_should_only_emit_post_create_signal_once(self, mocked_signal): + # Arrange + signal_called_with = {} + + def post_create_receiver( + sender, + objects: list[ModifiedObject[Post]], + tracking_info_: TrackingInfo | None = None, + **kwargs, + ): + signal_called_with["objects"] = objects + signal_called_with["tracking_info_"] = tracking_info_ + + post_create_signal.connect(post_create_receiver, sender=Post) + + # Act + Post.objects.create(title="Sound of Winter", publish_date="1998-03-08", author=self.author_john) + + # Assert + self.assertEqual(mocked_signal.call_count, 1, msg="The signal wasn't called once") + + @patch('bulk_tracker.signals.post_create_signal.send') + def test_model_bulk_create_should_only_emit_post_create_signal_once(self, mocked_signal): + # Arrange + signal_called_with = {} + + def post_create_receiver( + sender, + objects: list[ModifiedObject[Post]], + tracking_info_: TrackingInfo | None = None, + **kwargs, + ): + signal_called_with["objects"] = objects + signal_called_with["tracking_info_"] = tracking_info_ + + post_create_signal.connect(post_create_receiver, sender=Post) + + posts = [ + Post(title="Sound of Winter", publish_date="1998-01-08", author=self.author_john), + Post(title="Sound of Summer", publish_date="1998-06-08", author=self.author_john), + ] + + # Act + Post.objects.bulk_create(posts) + + # Assert + self.assertEqual(mocked_signal.call_count, 1, msg="The signal wasn't called once")