Working in django with data with a saved history of changes

I am creating an information system in which some entities have separate attributes or a set of them, for which it is necessary to store a history of changes with reference to the date of their relevance for further processing in conjunction with other entities. In particular, I have main entity Customer and one or a related set of date-related attributes (for example, the official names of Customer), which may change over time.

What is the best or possible way to implement the interaction of the model for main entity, but with their history must be preserved?

Here’s what I’ve come up with so far. The class code is probably redundant, but this is done specifically to demonstrate the problem.

Main class:

class Customer(models.Model):
name = models.CharField(max_length=128,
                        verbose_name='Customer system name')
# A key for relation with current value of secondary class
# I have doubts about the correctness of adding this field,
# but so far I have not come up with anything better.
legal_names = models.ForeignKey('CustomerNames', on_delete=models.SET_NULL,
                                null=True,
                                blank=True,
                                verbose_name='Legal customer names')

Auxiliary (secondary) class:

class CustomerNames(models.Model):
# A key for relation with the main model, specifying a list of names
customer = models.ForeignKey(Customer, on_delete=models.CASCADE,
                             related_name='customer_names',
                             verbose_name='Customer')
short_name = models.CharField(max_length=256,
                              verbose_name='Short name')
full_name = models.CharField(max_length=1024,
                             verbose_name='Full name')

# An attribute for determining the current value
# if we do not use a foreign key in the main class 
is_current = models.BooleanField(default=True,
                                 verbose_name='Is current value')
# Dates of relevance of the names
date_begin = models.DateField(verbose_name='Relevance begin date for names')
date_end = models.DateField(verbose_name='Relevance end date for names')

Accordingly, there is also a problem with the implementation of processing this model in the form and views. As an option for a foreign key in the main inlineformset model, but somehow it looks crooked.

Has anyone ever faced a similar problem and what was the solution?

In case you use Postgres you can use django pghistory a package that uses database triggers to save the history of all changes of a models field into an Event model. It's highly adaptable you can only track certain fields or adapt the Event model. Using db triggers has the additonal advantage that changes of a table are always tracked even when someone builds a view that forgets to save the Old data in the EventModel or if someone changes a row directly in the db.

https://django-pghistory.readthedocs.io/en/3.7.0/

@pghistory.track()
class Customer(models.Model):
   name = models.CharField(max_length=128,
       verbose_name='Customer system name'
   )

   short_name = models.CharField(max_length=256,
                              verbose_name='Short name')
   full_name = models.CharField(max_length=1024,
                             verbose_name='Full name')

You add the fields you had in your CustomerNames Model into the main model and add the pghistory.track decorator. This will add an CustomerEventModel which tracks by default all changes for every field of the tracked model. Further more it has several metadata fields like timestamps which will thus allow you to query the validity of particulars customers name in time. You can restrict the tracking also to certain fields ore create a fully customized EventModel for Customer (see pg history docs).

In your views you can extract the model history with your users. With regard to forms you just use to main model.

Вернуться на верх