5

I'm using django-simple-history: http://django-simple-history.readthedocs.io/en/latest/
I have a model, which I would like to apply its methods on an historical instance. Example:

from simple_history.models import HistoricalRecords

class Person(models.Model):
   firstname = models.CharField(max_length=20)
   lastname = models.CharField(max_length=20)
   history = HistoricalRecords()
   def fullName(self):
       return firstname + lastname

person = Person.objects.get(pk=1) # Person instance
for historyPerson in person.history:
    historyPerson.fullName() # wont work.

Since the class HistoricalPerson does not inherit the methods of Person. But using Person methods actually make sense, since they share the same fields..

Any solution for this? I'd prefer something simple, not like duplicating every method in my models for the history instances..

user3599803
  • 6,435
  • 17
  • 69
  • 130

2 Answers2

1

I found another workaround (maybe it's just the addon had been updated and got this feature). It's based on the documentation: adding-additional-fields-to-historical-models

HistoricalRecords field accepts bases parameter which sets a class that history objects will inherit. But you can't just set bases=[Person] inside Person class description, because it's not yet initialized.

So I ended up with an abstract class, which is inherited by both Person class and HistoricalRecords field. So the example from the question would look like:

class AbstractPerson(models.Model):
   class Meta:
       abstract = True

   firstname = models.CharField(max_length=20)
   lastname = models.CharField(max_length=20)

   def fullName(self):
       return firstname + lastname

class Person(AbstractPerson):
   history = HistoricalRecords(bases=[AbstractPerson])

And now history objects can use fullName method.

amoskaliov
  • 739
  • 4
  • 10
0

For anyone else having the same problem, I made it work by calling the method from the original class on the historical record object. So for the example in the question, a solution could be:

for historyPerson in person.history:
    Person.fullName(historyPerson)

This works because methods are very much like functions in Python, except that when you call a method on an instance, the instance is implicitly passed as the first parameter for the method. So if you have a class like:

class Foo:
    def method(self):
        ....

doing

f = Foo()
f.method()

is the same as:

f = Foo()
Foo.method(f)

I don't know exactly why simple-history does not copy the original model's methods though. One reason might be that since it allows you to exclude fields to be recorded, having the original methods might not make sense, since a method might not work if it uses fields that are not recorded in the historical record.

Yuzhe Chen
  • 11
  • 1