diff --git a/AKModel/availability/models.py b/AKModel/availability/models.py
index de51e438bf9ff427dff1714d0ad63267ecd7e278..805465432bfbd7af01ac16b15891dc15f2b0ba1e 100644
--- a/AKModel/availability/models.py
+++ b/AKModel/availability/models.py
@@ -247,7 +247,14 @@ class Availability(models.Model):
                 f'{self.end.astimezone(self.event.timezone).strftime("%a %H:%M")}')
 
     @classmethod
-    def with_event_length(cls, event, person=None, room=None, ak=None, ak_category=None):
+    def with_event_length(
+        cls,
+        event: Event,
+        person: AKOwner | None = None,
+        room: Room | None = None,
+        ak: AK | None = None,
+        ak_category: AKCategory | None = None,
+    ) -> "Availability":
         """
         Create an availability covering exactly the time between event start and event end.
         Can e.g., be used to create default availabilities.
@@ -268,7 +275,14 @@ class Availability(models.Model):
                                     room=room, ak=ak, ak_category=ak_category)
 
     @classmethod
-    def is_event_covered(cls, event, availabilities: List['Availability']) -> bool:
+    def is_event_covered(cls, event: Event, availabilities: List['Availability']) -> bool:
+        """Check if list of availibilities cover whole event.
+
+        :param event: event to check.
+        :param availabilities: availabilities to check.
+        :return: whether the availabilities cover full event.
+        :rtype: bool
+        """
         # NOTE: Cannot use `Availability.with_event_length` as its end is the
         #       event end + 1 day
         full_event = Availability(event=event, start=event.start, end=event.end)
diff --git a/AKModel/forms.py b/AKModel/forms.py
index f74dc39e5a73ed7d8bb248e3071300c093ebff74..74ca1b6813f0365d1179166da18aeb8a8c59ca4e 100644
--- a/AKModel/forms.py
+++ b/AKModel/forms.py
@@ -275,6 +275,7 @@ class RoomFormWithAvailabilities(AvailabilitiesFormMixin, RoomForm):
 
 
 class JSONImportForm(AdminIntermediateForm):
+    """Form to import an AK schedule from a json file."""
     json_data = forms.CharField(
         required=True,
         widget=forms.Textarea,
diff --git a/AKModel/models.py b/AKModel/models.py
index 3a91facb1319eb7b5b2c8d6850143888770615f0..491594273737d06db119c217a305000b86f9e486 100644
--- a/AKModel/models.py
+++ b/AKModel/models.py
@@ -8,7 +8,6 @@ from django.apps import apps
 from django.db.models import Count
 from django.urls import reverse_lazy
 from django.utils import timezone
-from django.utils.datetime_safe import datetime
 from django.utils.text import slugify
 from django.utils.translation import gettext_lazy as _
 from simple_history.models import HistoricalRecords
@@ -167,6 +166,24 @@ class Event(models.Model):
     def _generate_slots_from_block(
         self, start: datetime, end: datetime, slot_duration: timedelta, slot_index: int = 0
     ) -> Iterable[list[int, "Availability"]]:
+        """Discretize a time range into timeslots.
+
+        Uses a uniform discretization into blocks of length `slot_duration`,
+        starting at `start`. No incomplete timeslots are generated, i.e.
+        if (`end` - `start`) is not a whole number multiple of `slot_duration`
+        then the last incomplete timeslot is dropped.
+
+        :param start: Start of the time range.
+        :param end: Start of the time range.
+        :param slot_duration: Duration of a single timeslot in the discretization.
+        :param slot_index: index of the first timeslot. Defaults to 0.
+
+        :yield: Block of optimizer timeslots as the discretization result.
+        :ytype: list of tuples, each consisisting of the timeslot id
+            and its availability to indicate its start and duration.
+        """
+        # local import to prevent cyclic import
+        # pylint: disable=import-outside-toplevel
         from AKModel.availability.models import Availability
 
         current_slot_start = start
@@ -208,14 +225,32 @@ class Event(models.Model):
         return slot_index
 
     def uniform_time_slots(self, *, slots_in_an_hour=1.0) -> Iterable[list[int, "Availability"]]:
+        """Uniformly discretize the entire event into a single block of timeslots.
+
+        :param slots_in_an_hour: The percentage of an hour covered by a single slot.
+            Determines the discretization granularity.
+        :yield: Block of optimizer timeslots as the discretization result.
+        :ytype: a single list of tuples, each consisisting of the timeslot id
+            and its availability to indicate its start and duration.
+        """
         yield from self._generate_slots_from_block(
             start=self.start,
             end=self.end,
-            slot_duration=timedelta(hours=(1.0 / slots_in_an_hour)),
+            slot_duration=timedelta(hours=1.0 / slots_in_an_hour),
         )
 
     def default_time_slots(self, *, slots_in_an_hour=1.0) -> Iterable[list[int, "Availability"]]:
-        slot_duration = timedelta(hours=(1.0 / slots_in_an_hour))
+        """Discretize the all default slots into a blocks of timeslots.
+
+        In the discretization each default slot corresponds to one block.
+
+        :param slots_in_an_hour: The percentage of an hour covered by a single slot.
+            Determines the discretization granularity.
+        :yield: Block of optimizer timeslots as the discretization result.
+        :ytype: list of tuples, each consisisting of the timeslot id
+            and its availability to indicate its start and duration.
+        """
+        slot_duration = timedelta(hours=1.0 / slots_in_an_hour)
         slot_index = 0
 
         for block_slot in DefaultSlot.objects.filter(event=self).order_by("start", "end"):
@@ -228,6 +263,13 @@ class Event(models.Model):
             )
 
     def schedule_from_json(self, schedule: str) -> None:
+        """Load AK schedule from a json string.
+
+        :param schedule: A string that can be decoded to json, describing
+            the AK schedule. The json data is assumed to be constructed
+            following the output specification of the KoMa conference optimizer, cf.
+            https://github.com/Die-KoMa/ak-plan-optimierung/wiki/Input-&-output-format
+        """
         schedule = json.loads(schedule)
 
         slots_in_an_hour = schedule["input"]["timeslots"]["info"]["duration"]
@@ -602,6 +644,15 @@ class Room(models.Model):
         return self.title
 
     def as_json(self) -> str:
+        """Return a json string representation of this room object.
+
+        :return: The json string representation is constructed
+            following the input specification of the KoMa conference optimizer, cf.
+            https://github.com/Die-KoMa/ak-plan-optimierung/wiki/Input-&-output-format
+        :rtype: str
+        """
+        # local import to prevent cyclic import
+        # pylint: disable=import-outside-toplevel
         from AKModel.availability.models import Availability
 
         # check if room is available for the whole event
@@ -725,6 +776,15 @@ class AKSlot(models.Model):
         super().save(force_insert, force_update, using, update_fields)
 
     def as_json(self) -> str:
+        """Return a json string representation of the AK object of this slot.
+
+        :return: The json string representation is constructed
+            following the input specification of the KoMa conference optimizer, cf.
+            https://github.com/Die-KoMa/ak-plan-optimierung/wiki/Input-&-output-format
+        :rtype: str
+        """
+        # local import to prevent cyclic import
+        # pylint: disable=import-outside-toplevel
         from AKModel.availability.models import Availability
 
         # check if ak resp. owner is available for the whole event
@@ -738,9 +798,9 @@ class AKSlot(models.Model):
         def _owner_time_constraints(owner: AKOwner):
             if Availability.is_event_covered(self.event, owner.availabilities.all()):
                 return []
-            else:
-                return [f"availability-person-{owner.pk}"]
+            return [f"availability-person-{owner.pk}"]
 
+        # self.slots_in_an_hour is set in AKJSONExportView
         data = {
             "id": str(self.pk),
             "duration": int(self.duration * self.slots_in_an_hour),
diff --git a/AKModel/views/ak.py b/AKModel/views/ak.py
index 21a6fd72c8ebb5bd57183cb5ee5e536892c90b08..818f15d9ebe7e6a08e437f88fb9da6844cda179c 100644
--- a/AKModel/views/ak.py
+++ b/AKModel/views/ak.py
@@ -1,5 +1,4 @@
 import json
-from datetime import timedelta
 from typing import List
 
 from django.contrib import messages
@@ -7,6 +6,7 @@ from django.urls import reverse_lazy
 from django.utils.translation import gettext_lazy as _
 from django.views.generic import ListView, DetailView
 
+from AKModel.availability.models import Availability
 from AKModel.metaviews.admin import AdminViewMixin, FilterByEventSlugMixin, EventSlugMixin, IntermediateAdminView, \
     IntermediateAdminActionView
 from AKModel.models import AKRequirement, AKSlot, Event, AKOrgaMessage, AK, Room, AKOwner
@@ -50,25 +50,44 @@ class AKJSONExportView(AdminViewMixin, FilterByEventSlugMixin, ListView):
     context_object_name = "slots"
     title = _("AK JSON Export")
 
+    def _test_slot_contained(self, slot: Availability, availabilities: List[Availability]) -> bool:
+        return any(availability.contains(slot) for availability in availabilities)
+
+    def _test_event_covered(self, availabilities: List[Availability]) -> bool:
+        return not Availability.is_event_covered(self.event, availabilities)
+
+    def _test_fixed_ak(self, ak_id, slot: Availability, ak_fixed: dict) -> bool:
+        if not ak_id in ak_fixed:
+            return False
+
+        fixed_slot = Availability(self.event, start=ak_fixed[ak_id].start, end=ak_fixed[ak_id].end)
+        return fixed_slot.overlaps(slot, strict=True)
+
+    def _test_add_constraint(self, slot: Availability, availabilities: List[Availability]) -> bool:
+        return (
+            self._test_event_covered(availabilities)
+            and self._test_slot_contained(slot, availabilities)
+        )
+
+
     def get_queryset(self):
         return super().get_queryset().order_by("ak__track")
 
     def get_context_data(self, **kwargs):
-        from AKModel.availability.models import Availability
+        context = super().get_context_data(**kwargs)
+        context["participants"] = json.dumps([])
+
+        rooms = Room.objects.filter(event=self.event)
+        context["rooms"] = rooms
 
+        # TODO: Configure magic number in event
         SLOTS_IN_AN_HOUR = 1
 
-        rooms = Room.objects.filter(event=self.event)
-        participants = []
         timeslots = {
             "info": {"duration": (1.0 / SLOTS_IN_AN_HOUR), },
             "blocks": [],
             }
 
-        context = super().get_context_data(**kwargs)
-        context["rooms"] = rooms
-        context["participants"] = json.dumps(participants)
-
         for slot in context["slots"]:
             slot.slots_in_an_hour = SLOTS_IN_AN_HOUR
 
@@ -91,22 +110,6 @@ class AKJSONExportView(AdminViewMixin, FilterByEventSlugMixin, ListView):
             if (values := AKSlot.objects.select_related().filter(ak__pk=ak_id, fixed=True)).exists()
         }
 
-        def _test_slot_contained(slot: Availability, availabilities: List[Availability]) -> bool:
-            return any(availability.contains(slot) for availability in availabilities)
-
-        def _test_event_covered(slot: Availability, availabilities: List[Availability]) -> bool:
-            return not Availability.is_event_covered(self.event, availabilities)
-
-        def _test_fixed_ak(ak_id, slot: Availability) -> bool:
-            if not ak_id in ak_fixed:
-                return False
-
-            fixed_slot = Availability(self.event, start=ak_fixed[ak_id].start, end=ak_fixed[ak_id].end)
-            return fixed_slot.overlaps(slot, strict=True)
-
-        def _test_add_constraint(slot: Availability, availabilities: List[Availability]) -> bool:
-            return _test_event_covered(slot, availabilities) and _test_slot_contained(slot, availabilities)
-
         for block in self.event.default_time_slots(slots_in_an_hour=SLOTS_IN_AN_HOUR):
             current_block = []
 
@@ -119,17 +122,20 @@ class AKJSONExportView(AdminViewMixin, FilterByEventSlugMixin, ListView):
                 time_constraints.extend([
                     f"availability-ak-{ak_id}"
                     for ak_id, availabilities in ak_availabilities.items()
-                    if _test_add_constraint(slot, availabilities) or _test_fixed_ak(ak_id, slot)
+                    if (
+                        self._test_add_constraint(slot, availabilities)
+                        or self._test_fixed_ak(ak_id, slot, ak_fixed)
+                    )
                 ])
                 time_constraints.extend([
                     f"availability-person-{person_id}"
                     for person_id, availabilities in person_availabilities.items()
-                    if _test_add_constraint(slot, availabilities)
+                    if self._test_add_constraint(slot, availabilities)
                 ])
                 time_constraints.extend([
                     f"availability-room-{room_id}"
                     for room_id, availabilities in room_availabilities.items()
-                    if _test_add_constraint(slot, availabilities)
+                    if self._test_add_constraint(slot, availabilities)
                 ])
 
                 current_block.append({
diff --git a/AKModel/views/manage.py b/AKModel/views/manage.py
index f4564f0903f22d0345d04f6deffa21a67d28585b..ec5076fbd850c71a6f7d1a1d202a46461e43ebbd 100644
--- a/AKModel/views/manage.py
+++ b/AKModel/views/manage.py
@@ -60,7 +60,7 @@ class ExportSlidesView(EventSlugMixin, IntermediateAdminView):
             Create a list of tuples cosisting of an AK and a list of upcoming AKs (list length depending on setting)
             """
             next_aks_list = zip_longest(*[ak_list[i + 1:] for i in range(NEXT_AK_LIST_LENGTH)], fillvalue=None)
-            return [(ak, next_aks) for ak, next_aks in zip_longest(ak_list, next_aks_list, fillvalue=[])]
+            return list(zip_longest(ak_list, next_aks_list, fillvalue=[]))
 
         # Get all relevant AKs (wishes separately, and either all AKs or only those who should directly or indirectly
         # be presented when restriction setting was chosen)
@@ -250,6 +250,9 @@ class AKsByUserView(AdminViewMixin, EventSlugMixin, DetailView):
 
 
 class AKJSONImportView(EventSlugMixin, IntermediateAdminView):
+    """
+    View: Import an AK schedule from a json file that can be pasted into this view.
+    """
     form_class = JSONImportForm
     title = _("AK JSON Import")