Skip to content

Commit 8bbcf56

Browse files
author
Stefan Borer
authored
feat: add default_date optional parameter for bulk create and update (#687)
* feat: add default_date optional parameter for bulk create and update * chore: appy `make format`
1 parent fdc045e commit 8bbcf56

File tree

6 files changed

+62
-9
lines changed

6 files changed

+62
-9
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Authors
9494
- Sergey Ozeranskiy (`ozeranskiy <https://github.com/ozeranskiy>`_)
9595
- Shane Engelman
9696
- Steeve Chailloux
97+
- Stefan Borer (`sbor23 <https://github.com/sbor23>`_)
9798
- Steven Klass
9899
- Tommy Beadle (`tbeadle <https://github.com/tbeadle>`_)
99100
- Trey Hunner (`treyhunner <https://github.com/treyhunner>`_)

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 default date to ``bulk_create_with_history`` and ``bulk_update_with_history`` (gh-687)
7+
48
2.11.0 (2020-06-20)
59
-------------------
610
- Added ``clean_old_history`` management command (gh-675)

docs/common_issues.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,20 @@ history:
3333
1000
3434
3535
If you want to specify a change reason or history user for each record in the bulk create,
36-
you can add `_change_reason` or `_history_user` on each instance:
36+
you can add `_change_reason`, `_history_user` or `_history_date` on each instance:
3737

3838
.. code-block:: pycon
3939
4040
>>> for poll in data:
4141
poll._change_reason = 'reason'
4242
poll._history_user = my_user
43+
poll._history_date = some_date
4344
>>> objs = bulk_create_with_history(data, Poll, batch_size=500)
4445
>>> Poll.history.get(id=data[0].id).history_change_reason
4546
'reason'
4647
4748
You can also specify a default user or default change reason responsible for the change
48-
(`_history_user` and `_change_reason` take precedence).
49+
(`_change_reason`, `_history_user` and `_history_date` take precedence).
4950

5051
.. code-block:: pycon
5152

simple_history/manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def bulk_history_create(
107107
update=False,
108108
default_user=None,
109109
default_change_reason="",
110+
default_date=None,
110111
):
111112
"""
112113
Bulk create the history for the objects specified by objs.
@@ -126,7 +127,9 @@ def bulk_history_create(
126127
default_user or self.model.get_default_history_user(instance),
127128
)
128129
row = self.model(
129-
history_date=getattr(instance, "_history_date", timezone.now()),
130+
history_date=getattr(
131+
instance, "_history_date", default_date or timezone.now()
132+
),
130133
history_user=history_user,
131134
history_change_reason=get_change_reason_from_object(instance)
132135
or default_change_reason,

simple_history/tests/tests/test_utils.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from unittest import skipIf
2+
from datetime import datetime
23

34
import django
45
from django.contrib.auth import get_user_model
@@ -70,6 +71,14 @@ def test_bulk_create_history_with_default_change_reason(self):
7071
)
7172
)
7273

74+
def test_bulk_create_history_with_default_date(self):
75+
date = datetime(2020, 7, 1)
76+
bulk_create_with_history(self.data, Poll, default_date=date)
77+
78+
self.assertTrue(
79+
all([history.history_date == date for history in Poll.history.all()])
80+
)
81+
7382
def test_bulk_create_history_num_queries_is_two(self):
7483
with self.assertNumQueries(2):
7584
bulk_create_with_history(self.data, Poll)
@@ -175,7 +184,11 @@ def test_bulk_create_no_ids_return(self, hist_manager_mock):
175184
result = bulk_create_with_history(objects, model)
176185
self.assertEqual(result, objects)
177186
hist_manager_mock().bulk_history_create.assert_called_with(
178-
objects, batch_size=None, default_user=None, default_change_reason=None
187+
objects,
188+
batch_size=None,
189+
default_user=None,
190+
default_change_reason=None,
191+
default_date=None,
179192
)
180193

181194

@@ -236,6 +249,21 @@ def test_bulk_update_history_with_default_change_reason(self):
236249
)
237250
)
238251

252+
def test_bulk_update_history_with_default_date(self):
253+
date = datetime(2020, 7, 1)
254+
bulk_update_with_history(
255+
self.data, Poll, fields=["question"], default_date=date
256+
)
257+
258+
self.assertTrue(
259+
all(
260+
[
261+
history.history_date == date
262+
for history in Poll.history.filter(history_type="~")
263+
]
264+
)
265+
)
266+
239267
def test_bulk_update_history_num_queries_is_two(self):
240268
with self.assertNumQueries(2):
241269
bulk_update_with_history(

simple_history/utils.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ def get_history_model_for_model(model):
4545

4646

4747
def bulk_create_with_history(
48-
objs, model, batch_size=None, default_user=None, default_change_reason=None
48+
objs,
49+
model,
50+
batch_size=None,
51+
default_user=None,
52+
default_change_reason=None,
53+
default_date=None,
4954
):
5055
"""
5156
Bulk create the objects specified by objs while also bulk creating
@@ -60,6 +65,8 @@ def bulk_create_with_history(
6065
record
6166
:param default_change_reason: Optional change reason to specify as the change_reason
6267
in each historical record
68+
:param default_date: Optional date to specify as the history_date in each historical
69+
record
6370
:return: List of objs with IDs
6471
"""
6572

@@ -74,6 +81,7 @@ def bulk_create_with_history(
7481
batch_size=batch_size,
7582
default_user=default_user,
7683
default_change_reason=default_change_reason,
84+
default_date=default_date,
7785
)
7886
if second_transaction_required:
7987
obj_list = []
@@ -88,13 +96,20 @@ def bulk_create_with_history(
8896
batch_size=batch_size,
8997
default_user=default_user,
9098
default_change_reason=default_change_reason,
99+
default_date=default_date,
91100
)
92101
objs_with_id = obj_list
93102
return objs_with_id
94103

95104

96105
def bulk_update_with_history(
97-
objs, model, fields, batch_size=None, default_user=None, default_change_reason=None,
106+
objs,
107+
model,
108+
fields,
109+
batch_size=None,
110+
default_user=None,
111+
default_change_reason=None,
112+
default_date=None,
98113
):
99114
"""
100115
Bulk update the objects specified by objs while also bulk creating
@@ -107,6 +122,8 @@ def bulk_update_with_history(
107122
record
108123
:param default_change_reason: Optional change reason to specify as the change_reason
109124
in each historical record
125+
:param default_date: Optional date to specify as the history_date in each historical
126+
record
110127
"""
111128
if django.VERSION < (2, 2,):
112129
raise NotImplementedError(
@@ -115,15 +132,14 @@ def bulk_update_with_history(
115132
)
116133
history_manager = get_history_manager_for_model(model)
117134
with transaction.atomic(savepoint=False):
118-
model.objects.bulk_update(
119-
objs, fields, batch_size=batch_size,
120-
)
135+
model.objects.bulk_update(objs, fields, batch_size=batch_size)
121136
history_manager.bulk_history_create(
122137
objs,
123138
batch_size=batch_size,
124139
update=True,
125140
default_user=default_user,
126141
default_change_reason=default_change_reason,
142+
default_date=default_date,
127143
)
128144

129145

0 commit comments

Comments
 (0)