diff --git a/aleksis/core/templates/core/crud_events.html b/aleksis/core/templates/core/crud_events.html
index 30c4ec464f29a8e99d7b6dd72c0bc824a9e9825f..d80fed9c93b37f5c9786d416038dbbb139176036 100644
--- a/aleksis/core/templates/core/crud_events.html
+++ b/aleksis/core/templates/core/crud_events.html
@@ -1,31 +1,33 @@
-{% load i18n %}
+{% load i18n data_helpers %}
 
 <ul class="collection">
   {% for event in obj.crud_events %}
     {% if no_m2m and event.event_type == event.M2M_CHANGE or event.event_type == event.M2M_CHANGE_REV %}
     {% else %}
       <li class="collection-item">
-        {% if event.event_type == event.CREATE %}
-          {% blocktrans with person=event.user.person %}
-            Created by {{ person }}
-          {% endblocktrans %}
-        {% elif event.event_type == event.UPDATE %}
-          {% blocktrans with person=event.user.person %}
-            Updated by {{ person }}
-          {% endblocktrans %}
-        {% elif event.event_type == event.DELETE %}
-          {% blocktrans with person=event.user.person %}
-            Deleted by {{ person }}
-          {% endblocktrans %}
-        {% elif event.event_type == event.M2M_CHANGE %}
-          {% blocktrans with person=event.user.person %}
-            Updated by {{ person }}
-          {% endblocktrans %}
-        {% elif event.event_type == event.M2M_CHANGE_REV %}
-          {% blocktrans with person=event.user.person %}
-            Updated by {{ person }}
-          {% endblocktrans %}
-        {% endif %}
+        <strong>
+          {% if event.event_type == event.CREATE %}
+            {% blocktrans with person=event.user.person %}
+              Created by {{ person }}
+            {% endblocktrans %}
+          {% elif event.event_type == event.UPDATE %}
+            {% blocktrans with person=event.user.person %}
+              Updated by {{ person }}
+            {% endblocktrans %}
+          {% elif event.event_type == event.DELETE %}
+            {% blocktrans with person=event.user.person %}
+              Deleted by {{ person }}
+            {% endblocktrans %}
+          {% elif event.event_type == event.M2M_CHANGE %}
+            {% blocktrans with person=event.user.person %}
+              Updated by {{ person }}
+            {% endblocktrans %}
+          {% elif event.event_type == event.M2M_CHANGE_REV %}
+            {% blocktrans with person=event.user.person %}
+              Updated by {{ person }}
+            {% endblocktrans %}
+          {% endif %}
+        </strong>
 
         <div class="left" style="margin-right: 10px;">
           {% if event.event_type == event.CREATE %}
@@ -43,6 +45,17 @@
         <div class="right">
           {{ event.datetime }}
         </div>
+        {% parse_json event.changed_fields as changed_fields %}
+        {% if changed_fields %}
+          <ul>
+            {% for field, change in changed_fields.items %}
+              {% verbose_name "homework" "assignment" field as verbose_name %}
+              <li>
+                {{ verbose_name }}: <s>{{ change.0 }}</s> → {{ change.1 }}
+              </li>
+            {% endfor %}
+          </ul>
+        {% endif %}
       </li>
     {% endif %}
   {% endfor %}
diff --git a/aleksis/core/templatetags/data_helpers.py b/aleksis/core/templatetags/data_helpers.py
index 19f286434db34eb9e74b88950b8d87ee854959ef..f7393c73fd86eba6f861f87e321bf8dc5cbce6fd 100644
--- a/aleksis/core/templatetags/data_helpers.py
+++ b/aleksis/core/templatetags/data_helpers.py
@@ -1,6 +1,8 @@
-from typing import Any
+import json
+from typing import Any, Optional, Union
 
 from django import template
+from django.contrib.contenttypes.models import ContentType
 
 register = template.Library()
 
@@ -16,3 +18,24 @@ def get_dict(value: Any, arg: Any) -> Any:
         return value[int(arg)]
     else:
         return None
+
+
+@register.simple_tag
+def verbose_name(app_label: str, model: str, field: Optional[str] = None) -> str:
+    """Get a verbose name of a model or a field by app label and model name."""
+    ct = ContentType.objects.get(app_label=app_label, model=model).model_class()
+
+    if field:
+        # Field
+        return ct._meta.get_field(field).verbose_name.title()
+    else:
+        # Whole model
+        return ct._meta.verbose_name.title()
+
+
+@register.simple_tag
+def parse_json(value: Optional[str] = None) -> Union[dict, None]:
+    """Template tag for parsing JSON from a string."""
+    if not value:
+        return None
+    return json.loads(value)
diff --git a/aleksis/core/tests/templatetags/test_data_helpers.py b/aleksis/core/tests/templatetags/test_data_helpers.py
index ce43e578dbd84f95ed96a6cf1426d615f7e9c816..176e08b22ecb252d5b0113583ab534f46e978072 100644
--- a/aleksis/core/tests/templatetags/test_data_helpers.py
+++ b/aleksis/core/tests/templatetags/test_data_helpers.py
@@ -1,4 +1,10 @@
-from aleksis.core.templatetags.data_helpers import get_dict
+import json
+
+import pytest
+
+from aleksis.core.templatetags.data_helpers import get_dict, parse_json, verbose_name
+
+pytestmark = pytest.mark.django_db
 
 
 def test_get_dict_object():
@@ -24,3 +30,24 @@ def test_get_dict_invalid():
     _foo = 12
 
     assert get_dict(_foo, "bar") is None
+
+
+def test_verbose_name_model():
+    assert verbose_name("core", "person") == "Person"
+
+
+def test_verbose_name_field():
+    assert verbose_name("core", "person", "first_name") == "First Name"
+
+
+def test_parse_json_json():
+    foo = {"foo": 12, "bar": "12", "baz": []}
+    foo_json = json.dumps(foo)
+
+    assert parse_json(foo_json) == foo
+    assert parse_json("{}") == {}
+
+
+def test_parse_json_empty():
+    assert parse_json(None) is None
+    assert parse_json("") is None