Repository: jazzband/django-simple-history

Issue:
Creating historical records for models with M2M fields to `"self"` causes `FieldError`
**Describe the bug**
*See title.*

**To Reproduce**
Steps to reproduce the behavior:
1. Given the following model:
   ```python
   class Person(models.Model):
       relations = models.ManyToManyField("self")
       history = HistoricalRecords(m2m_fields=[relations])
   ```
2. Run the following code (which should also create a historical record for the `Person` object):
   ```python
   Person.objects.create()
   ```
3. This will produce the following error:
   ```
   django.core.exceptions.FieldError: Cannot resolve keyword 'person' into field. Choices are: from_person, from_person_id, id, to_person, to_person_id
   ```

**Expected behavior**
That a model object and associated historical record were successfully created, and that the error was not raised.

**Environment (please complete the following information):**
 - OS: Windows 11 22H2
 - Django Simple History Version: [the current `master` branch](https://github.com/jazzband/django-simple-history/tree/636bcbc46d473862c000101ef040e4eda693117f)
 - Django Version: 4.1.6
 - Database Version: SQLite 3.38.4



Discussion:
I did this fix in my project.

Change
https://github.com/jazzband/django-simple-history/blob/321b78354f36ccea42375a5b698596412e10cf72/simple_history/models.py#L673

To

```python
rows = through_model.objects.all()
if field.related_model == original_instance.__class__:
    rows = rows.filter(models.Q(**{
        "from_"+through_field_name: instance,
    }) | models.Q(**{
        "to_"+through_field_name: instance,
    }))
else:
    rows = rows.filter(**{through_field_name: instance})
```
With @Vitalick solution implemented I realized the change history is only logged in one direction. 

For example, using the model above, if a relationship between person1 and person2 is created via person1, a historical record is only created for person1. To generate to corresponding record for person2, it must be saved separately.   


Resolving patch:
diff --git a/simple_history/models.py b/simple_history/models.py
--- 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})
 


Test patch:
diff --git a/simple_history/tests/models.py b/simple_history/tests/models.py
--- 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
--- 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):