django-simple-history
django-simple-history copied to clipboard
Error with identifiers with '/'
Describe the bug If the history is added to a model, which allows to have in his primary key a '/' this does store the history correctly in the database, but when trying to access the history of this through the Django administration panel if the object identifier has a '/' character it returns an error.
To Reproduce Steps to reproduce the behavior:
- Generate a model which allows us to add the value of the primary key and that it has a history. For example:
class Test(models.Model):
id = models.CharField(max_length=256, null=False, primary_key=True)
last_seen = models.DateTimeField(null=True)
history = HistoricalRecords()
def __str__(self):
return str(self.machine_id)
- Add the ability to display the history in the Django admin panel
admin_site.register(Test, SimpleHistoryAdmin)
- Add an element which has a '/' in its id, for example:
dsfSERGserfseRFSREE/DFEWdfawer34
- Modify this element to generate a history.
- Attempt to access the history and you get the error:
Internal Server Error: /admin/pr_test/test/dsfSERGserfseRFSREE_2FDFEWdfawer34/history/\n","stream":"stderr","time":"2024-01-19T10:51:46.594236044Z
Traceback (most recent call last):\n","stream":"stderr","time":"2024-01-19T10:51:46.594303279Z
File \"/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py\", line 55, in inner\n","stream":"stderr","time":"2024-01-19T10:51:46.594311074Z
response = get_response(request)\n","stream":"stderr","time":"2024-01-19T10:51:46.594318267Z
File \"/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py\", line 197, in _get_response\n","stream":"stderr","time":"2024-01-19T10:51:46.594324411Z
response = wrapped_callback(request, *callback_args, **callback_kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.594331416Z
File \"/usr/local/lib/python3.8/site-packages/django/contrib/admin/options.py\", line 688, in wrapper\n","stream":"stderr","time":"2024-01-19T10:51:46.594337845Z
return self.admin_site.admin_view(view)(*args, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.594344355Z
File \"/usr/local/lib/python3.8/site-packages/django/utils/decorators.py\", line 134, in _wrapper_view\n","stream":"stderr","time":"2024-01-19T10:51:46.594350491Z
response = view_func(request, *args, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.594356809Z
File \"/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py\", line 62, in _wrapper_view_func\n","stream":"stderr","time":"2024-01-19T10:51:46.594362856Z
response = view_func(request, *args, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.594369347Z
File \"/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py\", line 242, in inner\n","stream":"stderr","time":"2024-01-19T10:51:46.594375418Z
return view(request, *args, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.59438185Z
File \"/usr/local/lib/python3.8/site-packages/simple_history/admin.py\", line 96, in history_view\n","stream":"stderr","time":"2024-01-19T10:51:46.594387882Z
return self.render_history_view(\n","stream":"stderr","time":"2024-01-19T10:51:46.594394433Z
File \"/usr/local/lib/python3.8/site-packages/simple_history/admin.py\", line 223, in render_history_view\n","stream":"stderr","time":"2024-01-19T10:51:46.594400408Z
return render(request, template, context, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.59443811Z
File \"/usr/local/lib/python3.8/site-packages/django/shortcuts.py\", line 24, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594444819Z
content = loader.render_to_string(template_name, context, request, using=using)\n","stream":"stderr","time":"2024-01-19T10:51:46.594451161Z
File \"/usr/local/lib/python3.8/site-packages/django/template/loader.py\", line 62, in render_to_string\n","stream":"stderr","time":"2024-01-19T10:51:46.594457263Z
return template.render(context, request)\n","stream":"stderr","time":"2024-01-19T10:51:46.594468459Z
File \"/usr/local/lib/python3.8/site-packages/django/template/backends/django.py\", line 61, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.59447437Z
return self.template.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594483292Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 175, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594489332Z
return self._render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594495627Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 167, in _render\n","stream":"stderr","time":"2024-01-19T10:51:46.594506403Z
return self.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594512874Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594518863Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594525465Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594531886Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594538929Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594545255Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.59456309Z
File \"/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py\", line 157, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.59457142Z
return compiled_parent._render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594578125Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 167, in _render\n","stream":"stderr","time":"2024-01-19T10:51:46.594584301Z
return self.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594590697Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594596619Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594602818Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594609067Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594615642Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594621793Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594628113Z
File \"/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py\", line 157, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594639962Z
return compiled_parent._render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594646541Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 167, in _render\n","stream":"stderr","time":"2024-01-19T10:51:46.59465251Z
return self.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.59465887Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594664857Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.59467116Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594678265Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594684656Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594690906Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594698191Z
File \"/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py\", line 157, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594707931Z
return compiled_parent._render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594714342Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 167, in _render\n","stream":"stderr","time":"2024-01-19T10:51:46.594720984Z
return self.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594727348Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594733256Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594739582Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594745781Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.59475243Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594758504Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594764792Z
File \"/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py\", line 63, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594770615Z
result = block.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594776952Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594782926Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.59479004Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594796172Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594802738Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594808922Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594820218Z
File \"/usr/local/lib/python3.8/site-packages/django/template/defaulttags.py\", line 321, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594826187Z
return nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594832646Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594838597Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594844827Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594850999Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594857525Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594863561Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594871037Z
File \"/usr/local/lib/python3.8/site-packages/django/template/library.py\", line 278, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594877195Z
return t.render(new_context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594883577Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 177, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594889509Z
return self._render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594895776Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 167, in _render\n","stream":"stderr","time":"2024-01-19T10:51:46.594901789Z
return self.nodelist.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594908202Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594914084Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.59492026Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 1005, in \u003clistcomp\u003e\n","stream":"stderr","time":"2024-01-19T10:51:46.594926419Z
return SafeString(\"\".join([node.render_annotated(context) for node in self]))\n","stream":"stderr","time":"2024-01-19T10:51:46.594932741Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594938893Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594945405Z
File \"/usr/local/lib/python3.8/site-packages/django/template/defaulttags.py\", line 238, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594951335Z
nodelist.append(node.render_annotated(context))\n","stream":"stderr","time":"2024-01-19T10:51:46.594957729Z
File \"/usr/local/lib/python3.8/site-packages/django/template/base.py\", line 966, in render_annotated\n","stream":"stderr","time":"2024-01-19T10:51:46.594963697Z
return self.render(context)\n","stream":"stderr","time":"2024-01-19T10:51:46.594969921Z
File \"/usr/local/lib/python3.8/site-packages/django/template/defaulttags.py\", line 471, in render\n","stream":"stderr","time":"2024-01-19T10:51:46.594975724Z
url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)\n","stream":"stderr","time":"2024-01-19T10:51:46.594982098Z
File \"/usr/local/lib/python3.8/site-packages/django/urls/base.py\", line 88, in reverse\n","stream":"stderr","time":"2024-01-19T10:51:46.594989168Z
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)\n","stream":"stderr","time":"2024-01-19T10:51:46.594992871Z
File \"/usr/local/lib/python3.8/site-packages/django/urls/resolvers.py\", line 828, in _reverse_with_prefix\n","stream":"stderr","time":"2024-01-19T10:51:46.594994852Z
raise NoReverseMatch(msg)\n","stream":"stderr","time":"2024-01-19T10:51:46.594996882Z
django.urls.exceptions.NoReverseMatch: Reverse for 'pr_test_test_simple_history' with arguments '('dsfSERGserfseRFSREE/DFEWdfawer34', 2)' not found. 1 pattern(s) tried: ['admin/pr_test/test/([^/]+)/history/([^/]+)/$']\n","stream":"stderr","time":"2024-01-19T10:51:46.594998804Z
[19/Jan/2024 10:51:46] \"GET /admin/pr_test/test/dsfSERGserfseRFSREE_2FDFEWdfawer34/history/ HTTP/1.1\" 500 592490\n","stream":"stderr","time":"2024-01-19T10:51:46.59500174Z
Expected behavior It is expected to display the history of elements, as it does for elements that do not have the '/' character.
Environment (please complete the following information):
- OS: Ubuntu 22.04.3 LTS
- Django Simple History Version: 3.4.0
- Django Version: 4.2.7
Additional context With elements that do not contain '/' it works without any problem.
This error occurs while rendering object URL with primary key in Change History view. This line causes the issue.
Since, primary key contains "/" which is a reserved character in URLs, somehow the object.pk needs to be URL encoded.
I was able to fix this issue using admin_urlquote filter on object.pk. However, it breaks history form view as it receives encoded value in object id and object does not exist with this value.