def diff(object1, object2): """ Compares two objects (such as model instances) and returns an object that can be used to render the differences between the two objects. Example:: >>> m1 = Person(name="Philip") >>> m2 = Person(name="Phillip") >>> diff(m1, m2).as_dict() {'name': [{'equal': 'Phil'}, {'inserted': 'l'}, {'equal': 'ip'}]} >>> diff(m1, m2).as_html() u('<tr>' '<td colspan="2">name</td>' '</tr> '<tr>' '<td colspan="2">' '<span class="diff_equal">Phil</span>' '<ins>l</ins>' '<span class="diff_equal">ip</span>' '</td> '</tr>') This can work with versioned models, e.g.:: >> diff(m1.history.as_of(version=2), >> m2.history.as_of(version=3)).as_html() u('<tr>' '<td colspan="2">name</td>' '</tr> '<tr>' '<td colspan="2">' '<span class="diff_equal">Phil</span>' '<ins>l</ins>' '<span class="diff_equal">ip!</span>' '</td> '</tr>') Returns: An object that can be used to display differences. Object will be either BaseModelDiff or a subclass. Raises: DiffUtilNotFound: If there's no registered or inferred diff for the objects. """ if is_historical_instance(object1): object1 = object1.history_info._object if is_historical_instance(object2): object2 = object2.history_info._object diff_util = registry.get_diff_util(object1.__class__) return diff_util(object1, object2)
def get_diff(self): """ Returns: A dictionary that contains all field diffs, indexed by field name. """ if self._diff is not None: return self._diff diff = {} diff_utils = {} if self.fields: diff_fields = self.fields else: diff_fields = [f.name for f in self.model_class._meta.fields] for name in diff_fields: if isinstance(name, basestring): field = self.model_class._meta.get_field(name) if isinstance(field, (models.AutoField, )): continue diff_utils[name] = registry.get_diff_util(field.__class__) else: diff_utils[name[0]] = name[1] for field_name, diff_class in diff_utils.items(): if field_name in self.excludes: continue obj1 = getattr(self.model1, field_name) obj2 = getattr(self.model2, field_name) is_model_diff = issubclass(diff_class, BaseModelDiff) if is_model_diff: # Use the non-versioned class to do the diff on the # versioned fields. if is_historical_instance(obj1): base_class = obj1.version_info._object.__class__ else: base_class = obj1.__class__ diff[field_name] = diff_class(obj1, obj2, model_class=base_class, context=self.context) else: diff[field_name] = diff_class(obj1, obj2, context=self.context) self._diff = diff return diff
def get_diff(self): """ Returns: A dictionary that contains all field diffs, indexed by field name. """ if self._diff is not None: return self._diff diff = {} diff_utils = {} if self.fields: diff_fields = self.fields else: diff_fields = [f.name for f in self.model_class._meta.fields] for name in diff_fields: if isinstance(name, basestring): field = self.model_class._meta.get_field(name) if isinstance(field, (models.AutoField,)): continue diff_utils[name] = registry.get_diff_util(field.__class__) else: diff_utils[name[0]] = name[1] for field_name, diff_class in diff_utils.items(): if field_name in self.excludes: continue obj1 = getattr(self.model1, field_name) obj2 = getattr(self.model2, field_name) is_model_diff = issubclass(diff_class, BaseModelDiff) if is_model_diff: # Use the non-versioned class to do the diff on the # versioned fields. if is_historical_instance(obj1): base_class = obj1.history_info._object.__class__ else: base_class = obj1.__class__ diff[field_name] = diff_class(obj1, obj2, model_class=base_class) else: diff[field_name] = diff_class(obj1, obj2) self._diff = diff return diff