Skip to content

Commit 7b15389

Browse files
authored
Exclude ManyToManyFields when using bulk_create_with_history (#699)
* Add failing test for bulk_create_with_history * Exclude ManyToManyFields in bulk_create_with_history * Fix unrelated test failure * Format * Add myself to AUTHORS.rst * Add entry to CHANGES.rst
1 parent 8bbcf56 commit 7b15389

File tree

5 files changed

+43
-3
lines changed

5 files changed

+43
-3
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Authors
9595
- Shane Engelman
9696
- Steeve Chailloux
9797
- Stefan Borer (`sbor23 <https://github.com/sbor23>`_)
98+
- Steven Buss (`sbuss <https://github.com/sbuss>`_)
9899
- Steven Klass
99100
- Tommy Beadle (`tbeadle <https://github.com/tbeadle>`_)
100101
- Trey Hunner (`treyhunner <https://github.com/treyhunner>`_)

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Changes
44
Unreleased
55
----------
66
- Add default date to ``bulk_create_with_history`` and ``bulk_update_with_history`` (gh-687)
7+
- Exclude ManyToManyFields when using ``bulk_create_with_history`` (gh-699)
78

89
2.11.0 (2020-06-20)
910
-------------------

simple_history/tests/models.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,3 +693,13 @@ class ForeignKeyToSelfModel(models.Model):
693693
class Street(models.Model):
694694
name = models.CharField(max_length=150)
695695
log = HistoricalRecords(related_name="history")
696+
697+
698+
class BulkCreateManyToManyModelOther(models.Model):
699+
name = models.CharField(max_length=15, unique=True)
700+
701+
702+
class BulkCreateManyToManyModel(models.Model):
703+
name = models.CharField(max_length=15, unique=True)
704+
other = models.ManyToManyField(BulkCreateManyToManyModelOther)
705+
history = HistoricalRecords()

simple_history/tests/tests/test_utils.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from simple_history.exceptions import NotHistoricalModelError
1212
from simple_history.tests.models import (
13+
BulkCreateManyToManyModel,
1314
Document,
1415
Place,
1516
Poll,
@@ -179,7 +180,8 @@ def test_bulk_create_no_ids_return(self, hist_manager_mock):
179180
objects=Mock(
180181
bulk_create=Mock(return_value=[Place(name="Place 1")]),
181182
filter=Mock(return_value=objects),
182-
)
183+
),
184+
_meta=Mock(get_fields=Mock(return_value=[])),
183185
)
184186
result = bulk_create_with_history(objects, model)
185187
self.assertEqual(result, objects)
@@ -192,6 +194,22 @@ def test_bulk_create_no_ids_return(self, hist_manager_mock):
192194
)
193195

194196

197+
class BulkCreateWithManyToManyField(TestCase):
198+
def setUp(self):
199+
self.data = [
200+
BulkCreateManyToManyModel(name="Object 1"),
201+
BulkCreateManyToManyModel(name="Object 2"),
202+
BulkCreateManyToManyModel(name="Object 3"),
203+
BulkCreateManyToManyModel(name="Object 4"),
204+
BulkCreateManyToManyModel(name="Object 5"),
205+
]
206+
207+
def test_bulk_create_with_history(self):
208+
bulk_create_with_history(self.data, BulkCreateManyToManyModel)
209+
210+
self.assertEqual(BulkCreateManyToManyModel.objects.count(), 5)
211+
212+
195213
@skipIf(django.VERSION < (2, 2,), reason="bulk_update does not exist before 2.2")
196214
class BulkUpdateWithHistoryTestCase(TestCase):
197215
def setUp(self):

simple_history/utils.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import django
44
from django.db import transaction
5+
from django.db.models import ManyToManyField
56
from django.forms.models import model_to_dict
67

78
from simple_history.exceptions import NotHistoricalModelError
@@ -69,7 +70,13 @@ def bulk_create_with_history(
6970
record
7071
:return: List of objs with IDs
7172
"""
72-
73+
# Exclude ManyToManyFields because they end up as invalid kwargs to
74+
# model.objects.filter(...) below.
75+
exclude_fields = [
76+
field.name
77+
for field in model._meta.get_fields()
78+
if isinstance(field, ManyToManyField)
79+
]
7380
history_manager = get_history_manager_for_model(model)
7481
second_transaction_required = True
7582
with transaction.atomic(savepoint=False):
@@ -88,7 +95,10 @@ def bulk_create_with_history(
8895
with transaction.atomic(savepoint=False):
8996
for obj in objs_with_id:
9097
attributes = dict(
91-
filter(lambda x: x[1] is not None, model_to_dict(obj).items())
98+
filter(
99+
lambda x: x[1] is not None,
100+
model_to_dict(obj, exclude=exclude_fields).items(),
101+
)
92102
)
93103
obj_list += model.objects.filter(**attributes)
94104
history_manager.bulk_history_create(

0 commit comments

Comments
 (0)