def simple_compare_ManyToManyField(self, obj_compare): """ comma separated list of all m2m objects """ m2m1, m2m2 = obj_compare.get_many_to_many() old = ", ".join([str(item) for item in m2m1]) new = ", ".join([str(item) for item in m2m2]) html = html_diff(old, new) return html
def simple_compare_ManyToManyField(self, obj_compare): """ comma separated list of all m2m objects """ m2m1, m2m2 = obj_compare.get_many_to_many() old = ", ".join([unicode(item) for item in m2m1]) new = ", ".join([unicode(item) for item in m2m2]) html = html_diff(old, new) return html
def compare(request, initiative, version_id): versions = Version.objects.get_for_object(initiative) latest = versions.first() selected = versions.filter(id=version_id).first() compare = { key: mark_safe( html_diff(selected.field_dict.get(key, ''), latest.field_dict.get(key, ''))) for key in COMPARING_FIELDS } compare['went_public_at'] = initiative.went_public_at return { 'inner-fragments': { 'header': "", '.main': render_to_string("fragments/compare.html", context=dict(initiative=initiative, selected=selected, latest=latest, compare=compare), request=request) } }
def fallback_compare(self, obj_compare): """ Simply create a html diff from the repr() result. Used for every field which has no own compare method. """ value1, value2 = obj_compare.to_string() html = html_diff(value1, value2) return html
def fallback_compare(self, obj_compare): """ Simply create a html diff from the repr() result. Used for every field which has no own compare method. """ value1, value2 = obj_compare.to_string() html = html_diff(value1, value2) return html
def test_html_diff(): # small values -> ndiff html = html_diff( value1='one', value2='two', ) assert html == '<pre class="highlight"><del>- one</del>\n<ins>+ two</ins></pre>' # big values -> Google diff-match-patch html = html_diff( value1='more than 20 Characters or?', value2='More than 20 characters, or?', ) assert html == ( '<pre class="highlight">' '<del>m</del><ins>M</ins>ore than 20 <del>C</del><ins>c</ins>haracters<ins>,</ins> or?' '</pre>' )
def _render_diff(obj): result = "" try: diff = _get_diff_from_objects(obj) for key in diff: result += "<p>%s</p>" % key result += "<p>" + html_diff(diff[key]['prev'], diff[key]['current'], EFFICIENCY) + "</p>" except IndexError: result = "" except ValueError: result = "" return result
def generic_add_remove(self, raw_value1, raw_value2, value1, value2): if raw_value1 is None: # a new values was added: context = {"value": value2} return render_to_string("reversion-compare/compare_generic_add.html", context) elif raw_value2 is None: # the existing value was removed: context = {"value": value1} return render_to_string("reversion-compare/compare_generic_remove.html", context) else: html = html_diff(value1, value2) return html
def generic_add_remove(self, raw_value1, raw_value2, value1, value2): if raw_value1 is None: # a new values was added: context = {"value": value2} return render_to_string("reversion-compare/compare_generic_add.html", context) elif raw_value2 is None: # the existing value was removed: context = {"value": value1} return render_to_string("reversion-compare/compare_generic_remove.html", context) else: html = html_diff(value1, value2) return html
def _render_diff(obj): result = "" try: diff = _get_diff_from_objects(obj) for key in diff: result += "<p>%s</p>" % key result += "<p>" + html_diff( diff[key]['prev'], diff[key]['current'], EFFICIENCY) + "</p>" except IndexError: result = "" except ValueError: result = "" return result
def retrieve(self, request, *args, **kwargs): """ Формируем словарь с добавленными и удалёнными строками, а так же описание в подсвеченными участками, которые были изменены """ version = self.get_object() event = Event.objects.get(pk=version.object_id) text1 = event.description_full text2 = version.field_dict['description_full'] data = { 'highlight': html_diff(text1, text2), 'added': self.get_modified_lines(text1, text2, '+'), 'deleted': self.get_modified_lines(text1, text2, '-'), } return Response(data)
def compare_inline_obj(self, model_class, obj_compare): """ :param model_class: ex: BostonAphasiaSentecesWrittenDictation model class :param obj_compare: reversion object :return: html string """ result = "" # print ('****************') # for attr, value in obj_compare.__dict__.iteritems(): # print attr, value fields = [field for field in model_class._meta.fields] for field in fields: field_name = field.name field_verbose_name = field._verbose_name or '' # print ('****************') # print (obj_compare.M2O_CHANGE_INFO) # for attr, value in obj_compare.__dict__.iteritems(): # print attr, value if field_name not in ('id', 'bostonAphasia'): if obj_compare.M2O_CHANGE_INFO and 'changed_items' in obj_compare.M2O_CHANGE_INFO and len(obj_compare.M2O_CHANGE_INFO['changed_items']) > 0: c = CompareObjects(field=obj_compare.field, field_name=field_name, obj=obj_compare.obj, version1=obj_compare.M2O_CHANGE_INFO['changed_items'][0][0], version2=obj_compare.M2O_CHANGE_INFO['changed_items'][0][1], is_reversed=False) # if the object value changed, print the diff html if c.changed() and c.value1 != c.value2: result = u'%s<p>%s - %s<br>%s</p>' % ( result, field_name, field_verbose_name, html_diff(('- %s' % c.value1), ('+ %s' % c.value2))) if result: return mark_safe('<pre class="highlight">%s</pre>' % result) else: return
def compare(self, obj, version1, version2): """ Create a generic html diff from the obj between version1 and version2: A diff of every changes field values. This method should be overwritten, to create a nice diff view coordinated with the model. """ diff = [] # Create a list of all normal fields and append many-to-many fields fields = [field for field in obj._meta.fields] concrete_model = obj._meta.concrete_model properties = [name for name in dir(concrete_model) if isinstance(getattr(concrete_model, name), property)] fields += concrete_model._meta.many_to_many # This gathers the related reverse ForeignKey fields, so we can do ManyToOne compares self.reverse_fields = [] # From: http://stackoverflow.com/questions/19512187/django-list-all-reverse-relations-of-a-model for f in obj._meta.get_fields(): if isinstance(f, models.ForeignKey) and f not in fields: self.reverse_fields.append(f.rel) #print(self.reverse_fields) fields += self.reverse_fields has_unfollowed_fields = False for field in fields: # logger.debug("%s %s %s", field, field.db_type, field.get_internal_type()) try: field_name = field.name except: # is a reverse FK field field_name = field.field_name if self.compare_fields and field_name not in self.compare_fields: continue if self.compare_exclude and field_name in self.compare_exclude: continue is_reversed = field in self.reverse_fields obj_compare = CompareObjects(field, field_name, obj, version1, version2, self.revision_manager, is_reversed) #obj_compare.debug() is_related = obj_compare.is_related follow = obj_compare.follow if is_related and not follow: has_unfollowed_fields = True if not obj_compare.changed(): # Skip all fields that aren't changed continue html = self._get_compare(obj_compare) diff.append({ "field": field, "is_related": is_related, "follow": follow, "diff": html, }) for prop_name in properties: if self.compare_props and prop_name not in self.compare_props: continue if self.compare_exclude_props and prop_name in self.compare_exclude_props: continue prop_value = getattr(obj, prop_name) json1 = None json2 = None try: with transaction.atomic(): version1.revision.revert(delete=True) prop_value = getattr(version1.object_version.object, prop_name) json1 = json.dumps(prop_value, indent=4) version2.revision.revert(delete=True) prop_value = getattr(version2.object_version.object, prop_name) json2 = json.dumps(prop_value, indent=4) raise Exception # Raise an exception to undo the transaction and the revision. except Exception: pass if json1 != json2: html = html_diff(json1, json2) try: prop_name = concrete_model.PropertiesMeta.verbose[prop_name] except: prop_name = str.capitalize(prop_name) diff.append({ 'name': prop_name, 'diff': html, }) return diff, has_unfollowed_fields
def compare_raw(self, request, obj, version1, version2, compare_error, extra_context=None): """ Fallback: compare the raw json data. """ version1data = get_version_data(version1) version2data = get_version_data(version2) version1pformat = pformat(version1data) version2pformat = pformat(version2data) # TODO: Generate a nicer diff ;) diff_html = html_diff(version1pformat, version2pformat) opts = self.model._meta context = { **self.admin_site.each_context(request), "opts": opts, "app_label": opts.app_label, "model_name": capfirst(opts.verbose_name), "title": _("Compare %(name)s") % { "name": version1.object_repr }, "obj": obj, "compare_error": compare_error, "diff_html": diff_html, "version1": version1, "version2": version2, "changelist_url": reverse( f"{self.admin_site.name}:{opts.app_label}_{opts.model_name}_changelist" ), "original": obj, "history_url": reverse( f"{self.admin_site.name}:{opts.app_label}_{opts.model_name}_history", args=(quote(obj.pk), )), "save_url": reverse( f"{self.admin_site.name}:{opts.app_label}_{opts.model_name}_revision", args=(quote(version1.object_id), version1.id), ), } context.update(extra_context or {}) return render( request, self.compare_raw_template or self._get_template_list("compare_raw.html"), context)
def semantic_diff(left, right, field): left_txt = left.field_dict[field] or '' right_txt = right.field_dict[field] or '' return mark_safe(html_diff(left_txt, right_txt, cleanup=SEMANTIC))
def _get_compare(obj_compare): value1, value2 = obj_compare.to_string() html = html_diff(value1, value2) return html
def _get_compare(obj_compare): value1, value2 = obj_compare.to_string() html = html_diff(value1, value2) return html
def semantic_diff(left, right, field): left_txt = left.field_dict[field] or '' right_txt = right.field_dict[field] or '' return mark_safe(html_diff(left_txt, right_txt, cleanup=SEMANTIC))