Skip to content

Commit 85752c5

Browse files
xahgmahRoss Mechanic
authored andcommitted
Make bulk_create_with_history working not only with PostgreSQL (#578)
1 parent 467834f commit 85752c5

File tree

4 files changed

+35
-3
lines changed

4 files changed

+35
-3
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Authors
2929
- Daniil Skrobov (`yetanotherape <https://github.com/yetanotherape>`_)
3030
- David Grochowski (`ThePumpingLemma <https://github.com/ThePumpingLemma>`_)
3131
- David Hite
32+
- Dmytro Shyshov (`xahgmah <https://github.com/xahgmah>`_)
3233
- Eduardo Cuducos
3334
- Erik van Widenfelt (`erikvw <https://github.com/erikvw>`_)
3435
- Filipe Pina (@fopina)

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Changes
33

44
Unreleased
55
----------
6+
- Added support for bulk_create_with_history for databeses different from PostgreSQL (gh-577)
67
- Fixed DoesNotExist error when trying to get instance if object is deleted (gh-571)
78
- Fix `model_to_dict` to detect changes in a parent model when using
89
`inherit=True` (backwards-incompatible for users who were directly

simple_history/tests/tests/test_utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,18 @@ def test_bulk_create_fails_with_wrong_model(self):
112112

113113
self.assertEqual(Poll.objects.count(), 0)
114114
self.assertEqual(Poll.history.count(), 0)
115+
116+
@patch("simple_history.utils.get_history_manager_for_model")
117+
def test_bulk_create_no_ids_return(self, hist_manager_mock):
118+
objects = [Place(id=1, name="Place 1")]
119+
model = Mock(
120+
objects=Mock(
121+
bulk_create=Mock(return_value=[Place(name="Place 1")]),
122+
filter=Mock(return_value=objects),
123+
)
124+
)
125+
result = bulk_create_with_history(objects, model)
126+
self.assertEqual(result, objects)
127+
hist_manager_mock().bulk_history_create.assert_called_with(
128+
objects, batch_size=None
129+
)

simple_history/utils.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.db import transaction
2+
from django.forms.models import model_to_dict
23

34
from simple_history.exceptions import NotHistoricalModelError
45

@@ -40,16 +41,30 @@ def bulk_create_with_history(objs, model, batch_size=None):
4041
"""
4142
Bulk create the objects specified by objs while also bulk creating
4243
their history (all in one transaction).
44+
Because of not providing primary key attribute after bulk_create on any DB except
45+
Postgres (https://docs.djangoproject.com/en/2.2/ref/models/querysets/#bulk-create)
46+
Divide this process on two transactions for other DB's
4347
:param objs: List of objs (not yet saved to the db) of type model
4448
:param model: Model class that should be created
4549
:param batch_size: Number of objects that should be created in each batch
4650
:return: List of objs with IDs
4751
"""
4852

4953
history_manager = get_history_manager_for_model(model)
50-
54+
second_transaction_required = True
5155
with transaction.atomic(savepoint=False):
5256
objs_with_id = model.objects.bulk_create(objs, batch_size=batch_size)
53-
history_manager.bulk_history_create(objs_with_id, batch_size=batch_size)
54-
57+
if objs_with_id and objs_with_id[0].pk:
58+
second_transaction_required = False
59+
history_manager.bulk_history_create(objs_with_id, batch_size=batch_size)
60+
if second_transaction_required:
61+
obj_list = []
62+
with transaction.atomic(savepoint=False):
63+
for obj in objs_with_id:
64+
attributes = dict(
65+
filter(lambda x: x[1] is not None, model_to_dict(obj).items())
66+
)
67+
obj_list += model.objects.filter(**attributes)
68+
history_manager.bulk_history_create(obj_list, batch_size=batch_size)
69+
objs_with_id = obj_list
5570
return objs_with_id

0 commit comments

Comments
 (0)