Skip to content

Commit 20bdd25

Browse files
mscansianRoss Mechanic
authored andcommitted
Add pre and post create_historical_record signals (#426)
* Add signals to create_historical_record * Update docs to include signals * Update pre_create_historical_record sender class * Add tests to signal sender * Fix signal sender using the wrong class * Add Matheus Cansian to AUTHORS * Update CHANGES
1 parent 78ac5a7 commit 20bdd25

File tree

6 files changed

+110
-4
lines changed

6 files changed

+110
-4
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Authors
6565
- Kyle Seever
6666
- Adnan Umer (@uadnan)
6767
- Jonathan Zvesper (@zvesp)
68+
- Matheus Cansian (@mscansian)
6869

6970
Background
7071
==========

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Changes
22
=======
33

4+
Unreleased
5+
------------------
6+
- Add pre and post create_historical_record signals (gh-426)
7+
48
2.3.0 (2018-07-19)
59
------------------
610
- Add ability to diff HistoricalRecords (gh-244)

docs/advanced.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,3 +446,23 @@ This may be useful when you want to construct timelines and need to get only the
446446
delta = new_record.diff_against(old_record)
447447
for change in delta.changes:
448448
print("{} changed from {} to {}".format(change.field, change.old, change.new))
449+
450+
Using signals
451+
------------------------------------
452+
django-simple-history includes signals that helps you provide custom behaviour when saving a historical record. If you want to connect the signals you can do so using the following code:
453+
454+
.. code-block:: python
455+
456+
from django.dispatch import receiver
457+
from simple_history.signals import (
458+
pre_create_historical_record,
459+
post_create_historical_record
460+
)
461+
462+
@receiver(pre_create_historical_record)
463+
def pre_create_historical_record(sender, instance, **kwargs):
464+
print("Sent before saving historical record")
465+
466+
@receiver(pre_create_historical_record)
467+
def post_create_historical_record(sender, instance, history_instance, **kwargs):
468+
print("Sent after saving historical record")

simple_history/models.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020

2121
from . import exceptions
2222
from .manager import HistoryDescriptor
23+
from .signals import (
24+
pre_create_historical_record,
25+
post_create_historical_record,
26+
)
2327

2428
registered_models = {}
2529

@@ -342,14 +346,29 @@ def create_historical_record(self, instance, history_type):
342346
history_date = getattr(instance, '_history_date', now())
343347
history_user = self.get_history_user(instance)
344348
history_change_reason = getattr(instance, 'changeReason', None)
345-
346349
manager = getattr(instance, self.manager_name)
350+
351+
pre_create_historical_record.send(
352+
sender=manager.model, instance=instance,
353+
history_date=history_date, history_user=history_user,
354+
history_change_reason=history_change_reason,
355+
)
356+
347357
attrs = {}
348358
for field in self.fields_included(instance):
349359
attrs[field.attname] = getattr(instance, field.attname)
350-
manager.create(history_date=history_date, history_type=history_type,
351-
history_user=history_user,
352-
history_change_reason=history_change_reason, **attrs)
360+
history_instance = manager.create(
361+
history_date=history_date, history_type=history_type,
362+
history_user=history_user,
363+
history_change_reason=history_change_reason, **attrs
364+
)
365+
366+
post_create_historical_record.send(
367+
sender=manager.model, instance=instance,
368+
history_instance=history_instance,
369+
history_date=history_date, history_user=history_user,
370+
history_change_reason=history_change_reason,
371+
)
353372

354373
def get_history_user(self, instance):
355374
"""Get the modifying user from instance or middleware."""

simple_history/signals.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import django.dispatch
2+
3+
4+
pre_create_historical_record = django.dispatch.Signal(providing_args=[
5+
'instance', 'history_date', 'history_user', 'history_change_reason',
6+
])
7+
post_create_historical_record = django.dispatch.Signal(providing_args=[
8+
'instance', 'history_instance', 'history_date', 'history_user',
9+
'history_change_reason',
10+
])
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from __future__ import unicode_literals
2+
3+
from datetime import datetime
4+
5+
from django.test import TestCase
6+
7+
from simple_history.signals import (
8+
pre_create_historical_record,
9+
post_create_historical_record,
10+
)
11+
12+
from ..models import Poll
13+
14+
today = datetime(2021, 1, 1, 10, 0)
15+
16+
17+
class PrePostCreateHistoricalRecordSignalTest(TestCase):
18+
def setUp(self):
19+
self.signal_was_called = False
20+
self.signal_instance = None
21+
self.signal_history_instance = None
22+
self.signal_sender = None
23+
24+
def test_pre_create_historical_record_signal(self):
25+
def handler(sender, instance, **kwargs):
26+
self.signal_was_called = True
27+
self.signal_instance = instance
28+
self.signal_sender = sender
29+
pre_create_historical_record.connect(handler)
30+
31+
p = Poll(question="what's up?", pub_date=today)
32+
p.save()
33+
34+
self.assertTrue(self.signal_was_called)
35+
self.assertEqual(self.signal_instance, p)
36+
self.assertEqual(self.signal_sender, p.history.first().__class__)
37+
38+
def test_post_create_historical_record_signal(self):
39+
def handler(sender, instance, history_instance, **kwargs):
40+
self.signal_was_called = True
41+
self.signal_instance = instance
42+
self.signal_history_instance = history_instance
43+
self.signal_sender = sender
44+
post_create_historical_record.connect(handler)
45+
46+
p = Poll(question="what's up?", pub_date=today)
47+
p.save()
48+
49+
self.assertTrue(self.signal_was_called)
50+
self.assertEqual(self.signal_instance, p)
51+
self.assertTrue(self.signal_history_instance is not None)
52+
self.assertEqual(self.signal_sender, p.history.first().__class__)

0 commit comments

Comments
 (0)