I am curious if there is a way to see what has changed on an object after saving it using the Django Rest Framework. I have some special behavior I need to check if a field has been changed from its original value that I was hoping to handle using the post_save
on generics.RetrieveUpdateDestroyAPIView
.
My first thought was to check using pre_save
but it seems that pre_save
's object argument already has the changes applied to it.
OLD ANSWER for django rest framework version 2.3.12:
To check if anything has changed on update, you will have to compare the unchanged model instance which is self.object with the changed model instance which is serializer.object.
The object argument which is passed to the pre_save method is the serializer.object which is not yet saved in the database with the new changes.
The unchanged model instance is the self.object which has been fetched from the database using self.get_object_or_none(). Compare it with the obj argument in the pre_save method.
def pre_save(self,obj):
unchanged_instance = self.object
changed_instance = obj
..... # comparison code
NEW ANSWER for django rest framework 3.3:
pre_save
and post_save
are no longer valid.
Now you can place any pre save or post save logic in perform_update
method. For example:
def perform_update(self, serializer):
# NOTE: serializer.instance gets updated after calling save
# if you want to use the old_obj after saving the serializer you should
# use self.get_object() to get the old instance.
# other wise serializer.instance would do fine
old_obj = self.get_object()
new_data_dict = serializer.validated_data
# pre save logic
if old_obj.name != new_data_dict['name']:
do_something
.....
new_obj = serializer.save()
# post save logic
......
I was able to do this with help from model_utils FieldTracker. You can install a tracker on the relevant model, then in pre_save
(by post_save
it's too late) you can do this:
def pre_save(self, obj):
if hasattr(obj, 'tracker'):
self.changed_fields = obj.tracker.changed()
else:
self.changed_fields = None
changed_fields
will look like this: {'is_public': False, 'desc': None}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With