10

Well, I think the question explains itself.

I have two instances of a Django Model and I would like to know which fields differ.

How could you do this in a smart way?

Cheers!

gabn88
  • 781
  • 8
  • 23

2 Answers2

14

Lets says obj1 and obj2 are 2 instances of the model MyModel.

To know which fields differ on two instances of a Django model, we first get all the fields of a model and store it in a variable my_model_fields.

my_model_fields = MyModel._meta.get_all_field_names() # gives me the list of all the model fields defined in it

Then we apply filter() with lambda to know which fields differ between them.

filter(lambda field: getattr(obj1,field,None)!=getattr(obj2,field,None), my_model_fields)

The filter() function will return me the list of model fields which differ between the two instances.

Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126
  • Thanks for the quick response! I tried: my_model_fields = self._meta.get_all_field_names() # gives me the list of all the model fields defined in it filter(lambda field: getattr(self,field,None)!=getattr(orig,field,None), my_model_fields) ... Which is called in the save method of an instance, but I get: NameError self global name is not defined... Any suggestions? – gabn88 Jul 28 '15 at 17:30
  • Nevermind! If I do changed_fields = filter(lambda field: getattr(obj1,field,None)!=getattr(obj2,field,None), my_model_fields) I get back the changed fields! – gabn88 Jul 28 '15 at 17:41
  • Maybe I should do this in a follow-up question, but how can I now do: for field in changed_fields: qs =MyModel.objects.filter(something=something), qs.update(***FIELD*** = F(field)), how to do the ***FIELD**? – gabn88 Jul 28 '15 at 18:02
  • Your code with `self` is working in my case. I just tried it. Please check if you have access to `self` when you are calling `filter()` or you have specified `self` in the function signature of `save()`. – Rahul Gupta Jul 28 '15 at 18:09
  • 1
    It is working, thank you :) I also found the answer to my followup question, namely: **{field: F(field)} :) thank you again! – gabn88 Jul 28 '15 at 18:18
  • Great! Happy to help. :) Also check this link for updating multiple columns using F objects. http://stackoverflow.com/questions/15574187/update-multiple-columns-using-django-f-object – Rahul Gupta Jul 28 '15 at 18:22
  • 2
    Newer django versions should check [here](https://stackoverflow.com/a/3106314/2711654) for an alternative to `get_all_field_names`. – Spidey May 12 '21 at 15:30
2

This is how I get the difference between the two instances with the help of serializers and deepdiff. Why serializer? as we have to get the whole nested data of the instance for comparison.

  from deepdiff import DeepDiff
  .
  .
  .
  old_data = modelserilaizer(instance1).data
  new_data = modelserilaizer(instance2).data
  instance_diff = DeepDiff(old_data, new_data, ignore_order=True)
  # output {'values_changed': {"root['item'][3]['rr'][2]['rate']": {'new_value': '0.03', 'old_value': '0.02'}}}
  if "values_changed" in instance_diff:
    # do you work here

Nishant Singh
  • 477
  • 4
  • 8