Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - logging changes to a model

Tags:

django

I'm in the middle of porting an application from Codeigniter to Django. One of the features I want to try and re-create in Django is the ability to log any changes to model field values.

Where is the best place to put it? I have tried to put it in model & form save methods but not having any luck at the moment. Has anyone go any examples?

Basically:

if orig.emp_name != self.emp_name: ##Create record in changes table with old value, new value and date/time of the change

Is it possible to loop through all ModelForm fields to check for changes in values? I can type the above for each field but it would be better if it could be in a loop.

like image 895
user2355278 Avatar asked Oct 12 '13 16:10

user2355278


1 Answers

Here's how I've handled this and it's worked well so far:

# get current model instance to update
instance = MyModel.objects.get(id=id)

# use model_to_dict to convert object to dict (imported from django.forms.models import model_to_dict)
obj_dict = model_to_dict(instance)

# create instance of the model with this old data but do not save it
old_instance = MyModel(**obj_dict)

# update the model instance (there are multiple ways to do this)
MyModel.objects.filter(id=id).update(emp_name='your name') 

# get the updated object
updated_object = MyModel.objects.get(id=id)

# get list of fields in the model class
my_model_fields = [field.name for field in cls._meta.get_fields()]

# get list of fields if they are different
differences = list(filter(lambda field: getattr(updated_object, field, None)!= getattr(old_instance, field, None), my_model_fields))

The differences variable will give you the list of fields that are different between the two instances. I also found it helpful to add which model fields I don't want to check for differences (e.g. we know the updated_date will always be changed, so we don't need to keep track of it).

skip_diff_fields = ['updated_date']

my_model_fields = []
for field in cls._meta.get_fields():
    if field.name not in skip_diff_fields:
        my_model_fields.append(field.name)
like image 76
jurms22 Avatar answered Oct 21 '22 02:10

jurms22