diff --git a/AUTHORS.rst b/AUTHORS.rst index 875e0173b..12eeb4383 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -90,6 +90,7 @@ Authors - Lucas Wiman - Maciej "RooTer" UrbaƄski - Marcelo Canina (`marcanuy `_) +- Marco Sirabella - Mark Davidoff - Martin Bachwerk - Marty Alchin diff --git a/CHANGES.rst b/CHANGES.rst index 0e6660d5c..fbe4f979c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -24,6 +24,8 @@ Unreleased ``HistoricalRecords.context.request``) under some circumstances (gh-1188) - Made ``HistoryRequestMiddleware`` async-capable (gh-1209) - Fixed error when setting ``table_name`` with ``inherit=True`` (gh-1195) +- Fixed ``FieldError`` when creating historical records for many-to-many fields with + ``to="self"`` (gh-1218) 3.3.0 (2023-03-08) ------------------ diff --git a/simple_history/models.py b/simple_history/models.py index 19080a4d4..4ad5c2e9c 100644 --- a/simple_history/models.py +++ b/simple_history/models.py @@ -670,7 +670,8 @@ def create_historical_record_m2ms(self, history_instance, instance): insert_rows = [] - through_field_name = type(original_instance).__name__.lower() + # `m2m_field_name()` is part of Django's internal API + through_field_name = field.m2m_field_name() rows = through_model.objects.filter(**{through_field_name: instance}) diff --git a/simple_history/tests/models.py b/simple_history/tests/models.py index a41374d7d..5c1da32ad 100644 --- a/simple_history/tests/models.py +++ b/simple_history/tests/models.py @@ -200,6 +200,11 @@ class PollChildRestaurantWithManyToMany(PollParentWithManyToMany): _history_m2m_fields = [restaurants] +class PollWithSelfManyToMany(models.Model): + relations = models.ManyToManyField("self") + history = HistoricalRecords(m2m_fields=[relations]) + + class CustomAttrNameForeignKey(models.ForeignKey): def __init__(self, *args, **kwargs): self.attr_name = kwargs.pop("attr_name", None) diff --git a/simple_history/tests/tests/test_models.py b/simple_history/tests/tests/test_models.py index 2f98594a7..484df73f9 100644 --- a/simple_history/tests/tests/test_models.py +++ b/simple_history/tests/tests/test_models.py @@ -103,6 +103,7 @@ PollWithManyToManyCustomHistoryID, PollWithManyToManyWithIPAddress, PollWithNonEditableField, + PollWithSelfManyToMany, PollWithSeveralManyToMany, Province, Restaurant, @@ -1869,6 +1870,17 @@ def test_separation(self): self.assertEqual(add.restaurants.all().count(), 0) self.assertEqual(add.places.all().count(), 0) + def test_self_field(self): + poll1 = PollWithSelfManyToMany.objects.create() + poll2 = PollWithSelfManyToMany.objects.create() + + self.assertEqual(poll1.history.all().count(), 1) + + poll1.relations.add(poll2) + self.assertIn(poll2, poll1.relations.all()) + + self.assertEqual(poll1.history.all().count(), 2) + class ManyToManyWithSignalsTest(TestCase): def setUp(self):