Repository: jazzband/django-simple-history

Issue:
Models with the same model name in various applications causes error
I have two applications in my project that use models with the same name. Please have a look at the following code snippets:

Application "meeting":

```
class Meeting(models.Model):
    # a lot of fields
    history = HistoricalRecords()

class Participant(models.Model):
    # a lot of fields 
    meeting = models.ForeignKey(Meeting)
    history = HistoricalRecords()
```

Application "poll":

```
class Poll(models.Model):
    # a lot of fields   
    history = HistoricalRecords()

class Participant(models.Model):
    # a lot of fields 
    poll = models.ForeignKey(Poll)
    history = HistoricalRecords()
```

When I try to validate my model with ./manage.py validate I get the error below:

CommandError: One or more models did not validate:
poll.historicalparticipant: Accessor for field 'history_user' clashes with related field 'User.historicalparticipant_set'. Add a related_name argument to the definition for 'history_user'.
meeting.historicalparticipant: Accessor for field 'history_user' clashes with related field 'User.historicalparticipant_set'. Add a related_name argument to the definition for 'history_user'.

I did some research and tracked the problem down to the method get_extra_fields in models.py. The problem occurs in line 181 where the value 'history_user' is set with the foreign key for the user model.

When I add a related_name parameter to the ForeignKey object, my example above works fine. Here are the code changes I made:

```
def get_extra_fields(self, model, fields):
    # ..... a lot of code :-)

    related_name = model._meta.app_label + "__" + model._meta.object_name
    return {
        'history_id': models.AutoField(primary_key=True),
        'history_date': models.DateTimeField(),
        # ADDED related_name
        'history_user': models.ForeignKey(user_model, null=True, related_name=related_name),
        'history_type': models.CharField(max_length=1, choices=(
            ('+', 'Created'),
            ('~', 'Changed'),
            ('-', 'Deleted'),
        )),
        'history_object': HistoricalObjectDescriptor(model),
        'instance': property(get_instance),
        'instance_type': model,
        'revert_url': revert_url,
        '__str__': lambda self: '%s as of %s' % (self.history_object, self.history_date)
    }
```

Is there a possibility to configure simple_history component, so it can deal with the given example or is this a bug?

Cheers 
Christian



Discussion:
There is no mention of a related manager attribute on the project user model, so chalk it up to an undocumented feature. As some may be relying on it though, I definately aggree we should provide a way for `related_name` for the history models to be customized through a parameter.

Since the goal is to provide a simple solution to history tracking, I think we should also change the default `related_name` to `'+'` to make it an 'opt-in' feature.

@c-2002, would you be able to put something together? I'm sure you saw we already support some parameters to customize the `HistoricalRecords` setup.


Resolving patch:
diff --git a/simple_history/models.py b/simple_history/models.py
--- a/simple_history/models.py
+++ b/simple_history/models.py
@@ -57,8 +57,10 @@ def python_2_unicode_compatible(klass):
 class HistoricalRecords(object):
     thread = threading.local()
 
-    def __init__(self, verbose_name=None, bases=(models.Model,)):
+    def __init__(self, verbose_name=None, bases=(models.Model,),
+                 user_related_name=None):
         self.user_set_verbose_name = verbose_name
+        self.user_related_name = user_related_name
         try:
             if isinstance(bases, basestring):
                 raise TypeError
@@ -178,7 +180,8 @@ def get_instance(self):
         return {
             'history_id': models.AutoField(primary_key=True),
             'history_date': models.DateTimeField(),
-            'history_user': models.ForeignKey(user_model, null=True),
+            'history_user': models.ForeignKey(
+                user_model, null=True, related_name=self.user_related_name),
             'history_type': models.CharField(max_length=1, choices=(
                 ('+', 'Created'),
                 ('~', 'Changed'),


Test patch:
diff --git a/simple_history/tests/external/models/__init__.py b/simple_history/tests/external/models/__init__.py
--- a/simple_history/tests/external/models/__init__.py
+++ b/simple_history/tests/external/models/__init__.py
@@ -1,4 +1,18 @@
 from __future__ import unicode_literals
 
+from django.db import models
+from simple_history.models import HistoricalRecords
+
 from .model2 import ExternalModel2
 from .model4 import ExternalModel4
+
+
+class Poll(models.Model):
+    """Test model for same-named historical models
+
+    This model intentionally conflicts with the 'Polls' model in 'tests.models'.
+    """
+    history = HistoricalRecords(user_related_name='+')
+
+    class Meta:
+        app_label = 'external'