Skip to content

Commit

Permalink
Merge pull request #149 from jedie/issues148-incompatible-version-data
Browse files Browse the repository at this point in the history
Fix #148 add a compare fallback
  • Loading branch information
jedie authored Feb 24, 2021
2 parents c03fed8 + cb63680 commit 62d44c9
Show file tree
Hide file tree
Showing 25 changed files with 878 additions and 278 deletions.
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[flake8]
exclude = .pytest_cache, .virtualenv, *.egg-info
exclude = .tox/, */migrations/*
#ignore = E115,E124,E128,E265,E301,E309,E501
max-line-length = 119
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ django-reversion = "*"
diff-match-patch = "*"

[tool.poetry.dev-dependencies]
bx_py_utils = "*" # https://github.com/boxine/bx_py_utils
django-debug-toolbar = "*" # http://django-debug-toolbar.readthedocs.io/en/stable/changes.html
pytest = "*"
pytest-django = "*"
Expand Down
60 changes: 55 additions & 5 deletions reversion_compare/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
Admin extensions for django-reversion-compare
:copyleft: 2012-2019 by the django-reversion-compare team, see AUTHORS for more details.
:copyleft: 2012-2021 by the django-reversion-compare team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""


import logging

from django.conf import settings
Expand All @@ -19,10 +17,13 @@
from django.urls import path, reverse
from django.utils.text import capfirst
from django.utils.translation import ugettext as _
from reversion import RevertError
from reversion.admin import VersionAdmin
from reversion.models import Revision, Version

from reversion_compare.compare_raw import get_version_data, pformat
from reversion_compare.forms import SelectDiffForm
from reversion_compare.helpers import html_diff
from reversion_compare.mixins import CompareMethodsMixin, CompareMixin


Expand Down Expand Up @@ -72,6 +73,7 @@ def compare_sub_text(self, obj, version1, version2, value1, value2):

# Template file used for the compare view:
compare_template = "reversion-compare/compare.html"
compare_raw_template = "reversion-compare/compare_raw.html"

# change template from django-reversion to add compare selection form:
object_history_template = "reversion-compare/object_history.html"
Expand Down Expand Up @@ -163,7 +165,15 @@ def compare_view(self, request, object_id, extra_context=None):
next_version = queryset.filter(pk__gt=version_id2).last()
prev_version = queryset.filter(pk__lt=version_id1).first()

compare_data, has_unfollowed_fields = self.compare(obj, version1, version2)
try:
compare_data, has_unfollowed_fields = self.compare(obj, version1, version2)
except RevertError as err:
logger.exception('Fallback compare caused by: %s', err)
# A old version can't be loaded.
# e.g.: model was migrated and version JSON data not, see:
# https://github.com/etianen/django-reversion/issues/859
# Fallback to JSON compare
return self.compare_raw(request, obj, version1, version2, compare_error=err, extra_context=extra_context)

opts = self.model._meta

Expand Down Expand Up @@ -201,6 +211,44 @@ def compare_view(self, request, object_id, extra_context=None):
context.update(extra_context or {})
return render(request, self.compare_template or self._get_template_list("compare.html"), context)

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)


class CompareVersionAdmin(CompareMethodsMixin, BaseCompareVersionAdmin):
"""
Expand All @@ -224,7 +272,9 @@ class RevisionAdmin(admin.ModelAdmin):
admin.site.register(Revision, RevisionAdmin)

class VersionAdmin(admin.ModelAdmin):
list_display = ("object_repr", "revision", "object_id", "content_type", "format")
def comment(self, obj):
return obj.revision.comment
list_display = ("object_repr", "comment", "object_id", "content_type", "format")
list_display_links = ("object_repr", "object_id")
list_filter = ("content_type", "format")
search_fields = ("object_repr", "serialized_data")
Expand Down
42 changes: 42 additions & 0 deletions reversion_compare/compare_raw.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Helper to compare raw version data.
see: https://github.com/etianen/django-reversion/issues/859
:copyleft: 2021 by the django-reversion-compare team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""


import json
import pprint

from django.core.serializers.json import DjangoJSONEncoder
from reversion.models import Version


def get_version_data(version):
"""
Get field data from a Version instance.
"""
assert isinstance(version, Version)
assert version.format == 'json', f'{version.format!r} not supported (only JSON)'

json_string = version.serialized_data
version_data = json.loads(json_string)
# version_data looks like:
# [{'fields': {'info': 'Migration state 2 - version 4',
# 'number_then_text': 111,
# 'text': 'Now this is a short text!!!'},
# 'model': 'reversion_compare_tests.migrationmodel',
# 'pk': 1}]
assert len(version_data) == 1
fields_data = version_data[0]['fields']
return fields_data


def pformat(value):
try:
return DjangoJSONEncoder(indent=4, sort_keys=True, ensure_ascii=False).encode(value)
except TypeError:
# Fallback if values are not serializable with JSON:
return pprint.pformat(value, width=120)
Binary file modified reversion_compare/locale/de/LC_MESSAGES/django.mo
Binary file not shown.
179 changes: 94 additions & 85 deletions reversion_compare/locale/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,123 +7,132 @@ msgid ""
msgstr ""
"Project-Id-Version: reversion\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-02-03 08:31+0100\n"
"PO-Revision-Date: 2009-02-03 08:41+0100\n"
"Last-Translator: Jannis Leidel <[email protected]>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"POT-Creation-Date: 2021-02-24 07:38-0600\n"
"PO-Revision-Date: 2021-02-24 14:46+0100\n"
"Last-Translator: Jens Diemer\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language-Team: \n"
"X-Generator: Poedit 2.3\n"

#: admin.py:122 templates/reversion/change_list.html:8
#: templates/reversion/recover_list.html:9
#, python-format
msgid "Recover deleted %(name)s"
msgstr "Gelöschte %(name)s wiederherstellen"
msgid "Compare %(name)s"
msgstr "Vergleiche %(name)s"

#: admin.py:155
#, python-format
msgid "Reverted to previous version, saved on %(datetime)s"
msgstr "Zu vorheriger Version zurückgesetzt, %(datetime)s gespeichert"

#: admin.py:157
#, python-format
msgid ""
"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again "
"below."
msgid "Field didn't exist!"
msgstr ""
"%(model)s \"%(name)s\" wurde erfolgreich zurückgesetzt. Sie können mit der "
"Bearbeitung forfahren."

#: admin.py:227
#, python-format
msgid "Recover %s"
msgstr "%s wiederherstellen"

#: admin.py:243
#, python-format
msgid "Revert %(name)s"
msgstr "%(name)s zurücksetzen"

#: templates/reversion/change_list.html:11
#, python-format
msgid "Add %(name)s"
msgstr "%(name)s hinzufügen"

#: templates/reversion/object_history.html:8
msgid ""
"Choose a date from the list below to revert to a previous version of this "
"object."
msgid "compare"
msgstr ""
"Wählen Sie einen Zeitpunkt aus der untenstehenden Liste aus, um zu einer "
"vorherigen Version dieses Objektes zurückzukehren."

#: templates/reversion/object_history.html:15
#: templates/reversion/recover_list.html:21
msgid "Date/time"
msgstr "Datum/Zeit"

#: templates/reversion/object_history.html:16
msgid "User"
msgstr "Benutzer"

#: templates/reversion/object_history.html:17
msgid "Comment"
msgstr "Kommentar"

#: templates/reversion/object_history.html:23
#: templates/reversion/recover_list.html:28
msgid "DATETIME_FORMAT"
msgstr "j. N Y, H:i"

#: templates/reversion/object_history.html:31
msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgstr ""
"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
"über diese Verwaltungsseiten angelegt."

#: templates/reversion/recover_form.html:14
#: templates/reversion/recover_list.html:6
#: templates/reversion/revision_form.html:14
msgid "Home"
msgstr "Start"

#: templates/reversion/recover_form.html:17
#, python-format
msgid "Recover deleted %(verbose_name)s"
msgstr "Gelöschte %(verbose_name)s wiederherstellen"
msgid "History"
msgstr "Geschichte"

#: templates/reversion/recover_form.html:18
#, python-format
msgid "Recover %(name)s"
msgstr "%(name)s wiederherstellen"
msgid ""
"\n"
" Compare <strong>%(date1)s</strong> with <strong>%(date2)s</"
"strong>:\n"
" "
msgstr ""
"\n"
"Vergleiche <strong>%(date1)s</strong> mit <strong>%(date2)s</strong>:"

msgid "Go back to history list"
msgstr ""

msgid "Revert to this version"
msgstr ""

msgid "changed to:"
msgstr ""

#: templates/reversion/recover_form.html:24
msgid "Press the save button below to recover this version of the object."
msgstr "Sichern Sie, um diese Version des Objektes wiederherzustellen."
msgid "time since that date:"
msgstr ""

msgid "add:"
msgstr ""

msgid "remove:"
msgstr ""

msgid "previous"
msgstr ""

msgid "next"
msgstr ""

msgid "There are no differences."
msgstr "Es gibt keinen Unterschied."

msgid "Edit comment:"
msgstr "Kommentar:"

msgid "(no comment exists)"
msgstr "(Kein Kommentar Eingetragen)"

msgid "Note:"
msgstr ""

#: templates/reversion/recover_list.html:15
msgid ""
"Choose a date from the list below to recover a deleted version of an object."
"\n"
" Fields/entries marked with <sup class=\"follow\">*</sup> are not "
"under reversion control.\n"
" It may be that not all marked information are correct.\n"
" "
msgstr ""
"Wählen Sie einen Zeitpunk aus der untenstehenden Liste, um eine gelöschte "
"Version des Objektes wiederherzustellen."
"\n"
"Felder/Einträge die mit <sup class=\"follow\">*</sup> gekennzeichnet sind "
"nicht unter Reversion Konrolle.\n"
"Somit sind evtl. nicht alle Informationen korrekt."

#: templates/reversion/recover_list.html:35
msgid "There are no deleted objects to recover."
msgstr "Es sind keine gelöschten Objekte zur Wiederherstellung vorhanden."
msgid ""
"\n"
" This is the fallback compare, because the normal compare can't be "
"applied\n"
" between the two selected version:\n"
" "
msgstr ""
"\n"
"Dies ist ein Fallback-Vergleich, weil der normale Vergleich zwischen den "
"beiden\n"
"ausgewählten Versionen nicht angewendet werden kann:"

#: templates/reversion/revision_form.html:18
msgid "History"
msgstr "Geschichte"
msgid "Revert to the old version will probably not work!"
msgstr ""
"Das Rücksetzten auf eine alten Version wird wahrscheinlich nicht "
"funktionieren!"

#: templates/reversion/revision_form.html:19
#, python-format
msgid "Revert %(verbose_name)s"
msgstr "%(verbose_name)s zurücksetzen"
msgid "More info:"
msgstr ""

msgid ""
"Choose a date from the list below to revert to a previous version of this "
"object."
msgstr ""
"Wählen Sie einen Zeitpunkt aus der untenstehenden Liste aus, um zu einer "
"vorherigen Version dieses Objektes zurückzukehren."

#: templates/reversion/revision_form.html:32
msgid "Press the save button below to revert to this version of the object."
msgstr "Sichern Sie, um das Objekt zu dieser Version zurückzusetzen."
msgid ""
"This object doesn't have a change history. It probably wasn't added via this "
"admin site."
msgstr ""
"Dieses Objekt hat keine Änderungsgeschichte. Es wurde möglicherweise nicht "
"über diese Verwaltungsseiten angelegt."
Binary file modified reversion_compare/locale/el/LC_MESSAGES/django.mo
Binary file not shown.
Loading

0 comments on commit 62d44c9

Please sign in to comment.