Skip to content

Commit 66cb8e4

Browse files
Remove db constraint on historical user to prevent IntegrityError (#676)
* Remove db constraint on historical user to prevent IntegrityError when deleting user * added ``user_db_constraint`` param to history to avoid circular reference on delete (gh-676) * Move user_db_constraint to bottom parameter
1 parent 785deba commit 66cb8e4

File tree

5 files changed

+36
-2
lines changed

5 files changed

+36
-2
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Authors
6060
- Jonathan Sanchez
6161
- Jonathan Zvesper (`zvesp <https://github.com/zvesp>`_)
6262
- Josh Fyne
63+
- Keith Hackbarth
6364
- Kevin Foster
6465
- Klaas van Schelven
6566
- Kris Neuharth

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Changes
22
=======
33
2.10.1 (2020-06-16)
4+
- added ``user_db_constraint`` param to history to avoid circular reference on delete (gh-676)
45
- added ``clean_old_history`` management command (gh-675)
56

67
2.10.0 (2020-04-27)

simple_history/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,11 @@ def __init__(
8282
history_user_setter=_history_user_setter,
8383
related_name=None,
8484
use_base_model_db=False,
85+
user_db_constraint=True,
8586
):
8687
self.user_set_verbose_name = verbose_name
8788
self.user_related_name = user_related_name
89+
self.user_db_constraint = user_db_constraint
8890
self.table_name = table_name
8991
self.inherit = inherit
9092
self.history_id_field = history_id_field
@@ -342,6 +344,7 @@ def _get_history_user_fields(self):
342344
null=True,
343345
related_name=self.user_related_name,
344346
on_delete=models.SET_NULL,
347+
db_constraint=self.user_db_constraint,
345348
)
346349
}
347350

simple_history/tests/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,10 @@ class Document(models.Model):
214214

215215
@property
216216
def _history_user(self):
217-
return self.changed_by
217+
try:
218+
return self.changed_by
219+
except User.DoesNotExist:
220+
return None
218221

219222

220223
class Paper(Document):

simple_history/tests/tests/test_models.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,32 @@ def test_specify_history_user(self):
370370
[d.history_user for d in document.history.all()], [None, user2, user1]
371371
)
372372

373+
def test_specify_history_user_self_reference_delete(self):
374+
user1 = User.objects.create_user("user1", "[email protected]")
375+
user2 = User.objects.create_user("user2", "[email protected]")
376+
document = Document.objects.create(changed_by=user1)
377+
document.changed_by = user2
378+
document.save()
379+
document.changed_by = None
380+
document.save()
381+
self.assertEqual(
382+
[d.history_user for d in document.history.all()], [None, user2, user1]
383+
)
384+
385+
# Change back to user1
386+
document.changed_by = user1
387+
document.save()
388+
389+
# Deleting user1 will cascade delete the document,
390+
# but fails when it tries to make the historical
391+
# record for the deleted user1.
392+
# This test performs differently on Postgres vs. SQLite
393+
# because of how the two database handle database constraints
394+
try:
395+
user1.delete()
396+
except IntegrityError as e:
397+
self.fail(e)
398+
373399
def test_specify_history_date_1(self):
374400
temperature = Temperature.objects.create(
375401
location="London", temperature=14, _history_date=today
@@ -398,7 +424,7 @@ def test_non_default_primary_key_save(self):
398424
library.book = None
399425
library.save()
400426
self.assertEqual(
401-
[l.book_id for l in library.history.all()], [None, book2.pk, book1.pk]
427+
[lib.book_id for lib in library.history.all()], [None, book2.pk, book1.pk]
402428
)
403429

404430
def test_string_defined_foreign_key_save(self):

0 commit comments

Comments
 (0)