diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index ce997f31a12e056bf72aad7abe21242941e850fe..5a2f2d53e9acbc006c1ae8db472a88e071fd9212 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -4,6 +4,7 @@ from typing import Dict, Optional, Union
 from django.db.models import Exists, OuterRef, QuerySet
 from django.utils.translation import gettext as _
 
+import reversion
 from calendarweek import CalendarWeek
 
 from aleksis.apps.chronos.models import LessonPeriod
@@ -37,8 +38,10 @@ def mark_absent(
     wanted_week = CalendarWeek.from_date(day)
 
     # Get all lessons of this person on the specified day
-    lesson_periods = self.lesson_periods_as_participant.on_day(day).filter(
-        period__period__gte=from_period
+    lesson_periods = (
+        self.lesson_periods_as_participant.on_day(day)
+        .filter(period__period__gte=from_period)
+        .annotate_week(wanted_week)
     )
 
     if to_period:
@@ -46,21 +49,30 @@ def mark_absent(
 
     # Create and update all personal notes for the discovered lesson periods
     for lesson_period in lesson_periods:
-        personal_note, created = PersonalNote.objects.update_or_create(
-            person=self,
-            lesson_period=lesson_period,
-            week=wanted_week.week,
-            year=wanted_week.year,
-            defaults={"absent": absent, "excused": excused, "excuse_type": excuse_type},
-        )
-        personal_note.groups_of_person.set(self.member_of.all())
-
-        if remarks:
-            if personal_note.remarks:
-                personal_note.remarks += "; %s" % remarks
-            else:
-                personal_note.remarks = remarks
-            personal_note.save()
+        sub = lesson_period.get_substitution()
+        if sub and sub.is_cancelled:
+                continue
+
+        with reversion.create_revision():
+            personal_note, created = PersonalNote.objects.update_or_create(
+                person=self,
+                lesson_period=lesson_period,
+                week=wanted_week.week,
+                year=wanted_week.year,
+                defaults={
+                    "absent": absent,
+                    "excused": excused,
+                    "excuse_type": excuse_type,
+                },
+            )
+            personal_note.groups_of_person.set(self.member_of.all())
+
+            if remarks:
+                if personal_note.remarks:
+                    personal_note.remarks += "; %s" % remarks
+                else:
+                    personal_note.remarks = remarks
+                personal_note.save()
 
 
 @LessonPeriod.method
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 799e0d01a9d90dd611aca288d332f974a644554c..66f6477d22165c085abd0855502686d505d75c75 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -1,4 +1,5 @@
 from django.db import models
+from django.utils.formats import date_format
 from django.utils.translation import gettext_lazy as _
 
 from calendarweek import CalendarWeek
@@ -82,6 +83,25 @@ class PersonalNote(ExtensibleModel, WeekRelatedMixin):
             self.excuse_type = None
         super().save(*args, **kwargs)
 
+    def reset_values(self):
+        """Reset all saved data to default values.
+
+        .. warning ::
+
+            This won't save the data, please execute ``save`` extra.
+        """
+        defaults = PersonalNote()
+
+        self.absent = defaults.absent
+        self.late = defaults.late
+        self.excused = defaults.excused
+        self.excuse_type = defaults.excuse_type
+        self.remarks = defaults.remarks
+        self.extra_marks.clear()
+
+    def __str__(self):
+        return f"{date_format(self.date)}, {self.lesson_period}, {self.person}"
+
     class Meta:
         verbose_name = _("Personal note")
         verbose_name_plural = _("Personal notes")
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
index 7b53c558dab2e5cf5f35f5363568f224ae80f9b3..be134d99139fed49d0e93ee4c39d7e5dc5dedec3 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
@@ -32,6 +32,10 @@
               {% trans "Mark as" %}
               <input type="hidden" value="{{ note.pk }}" name="personal_note">
               {% include "alsijil/partials/mark_as_buttons.html" %}
+              <a class="btn-flat red-text" title="{% trans "Delete note" %}"
+                 href="{% url "delete_personal_note" note.pk %}">
+                <i class="material-icons center">cancel</i>
+              </a>
             </form>
           {% endif %}
           <i class="material-icons left red-text">warning</i>
@@ -47,6 +51,10 @@
               {% trans "Mark as" %}
               <input type="hidden" value="{{ note.pk }}" name="personal_note">
               {% include "alsijil/partials/mark_as_buttons.html" %}
+              <a class="btn-flat red-text" title="{% trans "Delete note" %}"
+                 href="{% url "delete_personal_note" note.pk %}">
+                <i class="material-icons center">cancel</i>
+              </a>
             </form>
           {% endif %}
         </li>
@@ -167,6 +175,10 @@
                         {% trans "Mark as" %}
                         <input type="hidden" value="{{ note.pk }}" name="personal_note">
                         {% include "alsijil/partials/mark_as_buttons.html" %}
+                        <a class="btn-flat red-text" title="{% trans "Delete note" %}"
+                           href="{% url "delete_personal_note" note.pk %}">
+                          <i class="material-icons center">cancel</i>
+                        </a>
                       </form>
                     {% endif %}
 
@@ -205,6 +217,10 @@
                         {% trans "Mark as" %}
                         <input type="hidden" value="{{ note.pk }}" name="personal_note">
                         {% include "alsijil/partials/mark_as_buttons.html" %}
+                        <a class="btn-flat red-text" title="{% trans "Delete note" %}"
+                           href="{% url "delete_personal_note" note.pk %}">
+                          <i class="material-icons center">cancel</i>
+                        </a>
                       </form>
                     {% endif %}
                   </div>
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 0482571bd3cd9cf7c7da4a15b4cd7fc3e0a58c36..e2bba60a0df002ccf4b110ea8ac5f1e22df8387a 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -29,6 +29,11 @@ urlpatterns = [
     path("persons/", views.my_students, name="my_students"),
     path("persons/<int:id_>/", views.overview_person, name="overview_person"),
     path("me/", views.overview_person, name="overview_me"),
+    path(
+        "notes/<int:pk>/delete/",
+        views.DeletePersonalNoteView.as_view(),
+        name="delete_personal_note",
+    ),
     path("absence/new", views.register_absence, name="register_absence"),
     path("extra_marks/", views.ExtraMarkListView.as_view(), name="extra_marks"),
     path(
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 3fb49fea616b6b7d8e0dfb770af80b32828c49e4..b3da8f289641c9df21fa14402e659688e2cd6b3f 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -7,7 +7,9 @@ from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse, reverse_lazy
 from django.utils.translation import ugettext as _
+from django.views.generic import DetailView
 
+import reversion
 from calendarweek import CalendarWeek
 from django_tables2 import SingleTableView
 from reversion.views import RevisionMixin
@@ -131,7 +133,8 @@ def lesson(
             if personal_note_formset.is_valid() and request.user.has_perm(
                 "alsijil.edit_lesson_personalnote", lesson_period
             ):
-                instances = personal_note_formset.save()
+                with reversion.create_revision():
+                    instances = personal_note_formset.save()
 
                 # Iterate over personal notes and carry changed absences to following lessons
                 for instance in instances:
@@ -530,7 +533,12 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
                             absent=True,
                             excused=False,
                         )
-                        notes.update(excused=True, excuse_type=excuse_type)
+                        for note in notes:
+                            note.excused = True
+                            note.excuse_type = excuse_type
+                            with reversion.create_revision():
+                                note.save()
+
                         messages.success(
                             request, _("The absences have been marked as excused.")
                         )
@@ -547,7 +555,8 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp
                         if note.absent:
                             note.excused = True
                             note.excuse_type = excuse_type
-                            note.save()
+                            with reversion.create_revision():
+                                note.save()
                             messages.success(
                                 request, _("The absence has been marked as excused.")
                             )
@@ -678,6 +687,19 @@ def register_absence(request: HttpRequest) -> HttpResponse:
     return render(request, "alsijil/absences/register.html", context)
 
 
+class DeletePersonalNoteView(DetailView):
+    model = PersonalNote
+    template_name = "core/pages/delete.html"
+
+    def post(self, request, *args, **kwargs):
+        note = self.get_object()
+        with reversion.create_revision():
+            note.reset_values()
+            note.save()
+        messages.success(request, _("The personal note has been deleted."))
+        return redirect("overview_person", note.person.pk)
+
+
 class ExtraMarkListView(PermissionRequiredMixin, SingleTableView):
     """Table of all extra marks."""