diff --git a/.docker/extra_requirements.txt b/.docker/extra_requirements.txt
index 55e14c229a0c7e179c89afe7ab63e9b574fbc70b..f8498f044fad1c233232723f0c40bca1a82bc536 100644
--- a/.docker/extra_requirements.txt
+++ b/.docker/extra_requirements.txt
@@ -1 +1 @@
-uwsgi==2.0.25.1
+uwsgi==2.0.28
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5855c87c8f33c1695f0fb005197a1fba63f1179b..5cb605d57647a7083c60cb64af9db563b906601c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: python:3.10
+image: python:3.11
 
 services:
   - mysql
@@ -26,22 +26,18 @@ cache:
     - pip install pylint-gitlab pylint-django
     - mysql --version
 
-check:
+migrations:
   extends: .before_script_template
   script:
-    - ./Utils/check.sh --all
-    - source venv/bin/activate
     - ./manage.py makemigrations --dry-run --check
 
 test:
   extends: .before_script_template
   script:
-    - source venv/bin/activate
     - echo "GRANT ALL on *.* to '${MYSQL_USER}';"| mysql -u root --password="${MYSQL_ROOT_PASSWORD}" -h mysql
-    - pip install pytest-cov unittest-xml-reporting beautifulsoup4
+    - pip install pytest-cov unittest-xml-reporting
     - coverage run --source='.' manage.py test --settings AKPlanning.settings_ci
   after_script:
-    - source venv/bin/activate
     - coverage report
     - coverage xml
   coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
@@ -56,8 +52,6 @@ lint:
   extends: .before_script_template
   stage: test
   script:
-    - source venv/bin/activate
-    - pip install beautifulsoup4
     - pylint --load-plugins pylint_django --django-settings-module=AKPlanning.settings_ci --rcfile pylintrc --exit-zero --output-format=text AK* | tee /tmp/pylint.txt
     - sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
     - pylint --load-plugins pylint_django --django-settings-module=AKPlanning.settings_ci --rcfile pylintrc --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter AK* > codeclimate.json
diff --git a/AKDashboard/tests.py b/AKDashboard/tests.py
index 65b59fd9cdea19830b87b2577f53886619277a27..59328adf517d22a1793df63f67782254b0958f94 100644
--- a/AKDashboard/tests.py
+++ b/AKDashboard/tests.py
@@ -1,11 +1,12 @@
 import zoneinfo
+
 from django.apps import apps
-from django.test import TestCase, override_settings
+from django.test import override_settings, TestCase
 from django.urls import reverse
 from django.utils.timezone import now
 
 from AKDashboard.models import DashboardButton
-from AKModel.models import Event, AK, AKCategory
+from AKModel.models import AK, AKCategory, Event
 from AKModel.tests.test_views import BasicViewTests
 
 
@@ -13,6 +14,7 @@ class DashboardTests(TestCase):
     """
     Specific Dashboard Tests
     """
+
     @classmethod
     def setUpTestData(cls):
         """
@@ -20,17 +22,17 @@ class DashboardTests(TestCase):
         """
         super().setUpTestData()
         cls.event = Event.objects.create(
-            name="Dashboard Test Event",
-            slug="dashboardtest",
-            timezone=zoneinfo.ZoneInfo("Europe/Berlin"),
-            start=now(),
-            end=now(),
-            active=True,
-            plan_hidden=False,
+                name="Dashboard Test Event",
+                slug="dashboardtest",
+                timezone=zoneinfo.ZoneInfo("Europe/Berlin"),
+                start=now(),
+                end=now(),
+                active=True,
+                plan_hidden=False,
         )
         cls.default_category = AKCategory.objects.create(
-            name="Test Category",
-            event=cls.event,
+                name="Test Category",
+                event=cls.event,
         )
 
     def test_dashboard_view(self):
@@ -62,12 +64,12 @@ class DashboardTests(TestCase):
 
         # History should be empty
         response = self.client.get(url)
-        self.assertQuerysetEqual(response.context["recent_changes"], [])
+        self.assertQuerySetEqual(response.context["recent_changes"], [])
 
         AK.objects.create(
-            name="Test AK",
-            category=self.default_category,
-            event=self.event,
+                name="Test AK",
+                category=self.default_category,
+                event=self.event,
         )
 
         # History should now contain one AK (Test AK)
@@ -154,8 +156,8 @@ class DashboardTests(TestCase):
         self.assertNotContains(response, "Dashboard Button Test")
 
         DashboardButton.objects.create(
-            text="Dashboard Button Test",
-            event=self.event
+                text="Dashboard Button Test",
+                event=self.event
         )
 
         response = self.client.get(url_event_dashboard)
diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po
index 38b3d54a9101367a201b23ac589ff61f217d7775..9ef95b03bc63a8bf36540a2e4b674d6c9e2b259a 100644
--- a/AKModel/locale/de_DE/LC_MESSAGES/django.po
+++ b/AKModel/locale/de_DE/LC_MESSAGES/django.po
@@ -2,7 +2,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-03-03 00:42+0000\n"
+"POT-Creation-Date: 2025-03-04 14:49+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -33,8 +33,8 @@ msgstr "Plan veröffentlichen"
 msgid "Unpublish plan"
 msgstr "Plan verbergen"
 
-#: AKModel/admin.py:170 AKModel/models.py:875 AKModel/models.py:1329
-#: AKModel/models.py:1365 AKModel/templates/admin/AKModel/aks_by_user.html:12
+#: AKModel/admin.py:170 AKModel/models.py:890 AKModel/models.py:1348
+#: AKModel/templates/admin/AKModel/aks_by_user.html:12
 #: AKModel/templates/admin/AKModel/status/event_aks.html:10
 #: AKModel/views/manage.py:75 AKModel/views/status.py:102
 msgid "AKs"
@@ -60,11 +60,11 @@ msgstr "In Wiki-Syntax exportieren"
 msgid "Cannot export AKs from more than one event at the same time."
 msgstr "Kann nicht AKs von mehreren Events zur selben Zeit exportieren."
 
-#: AKModel/admin.py:335 AKModel/views/ak.py:123
+#: AKModel/admin.py:335 AKModel/views/ak.py:120
 msgid "Reset interest in AKs"
 msgstr "Interesse an AKs zurücksetzen"
 
-#: AKModel/admin.py:345 AKModel/views/ak.py:138
+#: AKModel/admin.py:345 AKModel/views/ak.py:135
 msgid "Reset AKs' interest counters"
 msgstr "Interessenszähler der AKs zurücksetzen"
 
@@ -125,19 +125,19 @@ msgstr "Die eingegebene Verfügbarkeit enthält ein ungültiges Datum."
 msgid "Please fill in your availabilities!"
 msgstr "Bitte Verfügbarkeiten eintragen!"
 
-#: AKModel/availability/models.py:43 AKModel/models.py:166
-#: AKModel/models.py:654 AKModel/models.py:731 AKModel/models.py:764
-#: AKModel/models.py:790 AKModel/models.py:809 AKModel/models.py:865
-#: AKModel/models.py:1023 AKModel/models.py:1100 AKModel/models.py:1268
-#: AKModel/models.py:1325 AKModel/models.py:1516
+#: AKModel/availability/models.py:43 AKModel/models.py:177
+#: AKModel/models.py:667 AKModel/models.py:744 AKModel/models.py:777
+#: AKModel/models.py:803 AKModel/models.py:822 AKModel/models.py:880
+#: AKModel/models.py:1039 AKModel/models.py:1116 AKModel/models.py:1286
+#: AKModel/models.py:1344 AKModel/models.py:1536
 msgid "Event"
 msgstr "Event"
 
-#: AKModel/availability/models.py:44 AKModel/models.py:655
-#: AKModel/models.py:732 AKModel/models.py:765 AKModel/models.py:791
-#: AKModel/models.py:810 AKModel/models.py:866 AKModel/models.py:1024
-#: AKModel/models.py:1101 AKModel/models.py:1269 AKModel/models.py:1326
-#: AKModel/models.py:1517
+#: AKModel/availability/models.py:44 AKModel/models.py:668
+#: AKModel/models.py:745 AKModel/models.py:778 AKModel/models.py:804
+#: AKModel/models.py:823 AKModel/models.py:881 AKModel/models.py:1040
+#: AKModel/models.py:1117 AKModel/models.py:1287 AKModel/models.py:1345
+#: AKModel/models.py:1537
 msgid "Associated event"
 msgstr "Zugehöriges Event"
 
@@ -149,8 +149,8 @@ msgstr "Person"
 msgid "Person whose availability this is"
 msgstr "Person deren Verfügbarkeit hier abgebildet wird"
 
-#: AKModel/availability/models.py:61 AKModel/models.py:1027
-#: AKModel/models.py:1090 AKModel/models.py:1335
+#: AKModel/availability/models.py:61 AKModel/models.py:1043
+#: AKModel/models.py:1106 AKModel/models.py:1354
 msgid "Room"
 msgstr "Raum"
 
@@ -158,8 +158,8 @@ msgstr "Raum"
 msgid "Room whose availability this is"
 msgstr "Raum dessen Verfügbarkeit hier abgebildet wird"
 
-#: AKModel/availability/models.py:70 AKModel/models.py:874
-#: AKModel/models.py:1089 AKModel/models.py:1263
+#: AKModel/availability/models.py:70 AKModel/models.py:889
+#: AKModel/models.py:1105 AKModel/models.py:1281
 msgid "AK"
 msgstr "AK"
 
@@ -167,8 +167,8 @@ msgstr "AK"
 msgid "AK whose availability this is"
 msgstr "Verfügbarkeiten"
 
-#: AKModel/availability/models.py:79 AKModel/models.py:735
-#: AKModel/models.py:1341
+#: AKModel/availability/models.py:79 AKModel/models.py:748
+#: AKModel/models.py:1360
 msgid "AK Category"
 msgstr "AK-Kategorie"
 
@@ -176,7 +176,7 @@ msgstr "AK-Kategorie"
 msgid "AK Category whose availability this is"
 msgstr "AK-Kategorie, deren Verfügbarkeit hier abgebildet wird"
 
-#: AKModel/availability/models.py:309 AKModel/models.py:923
+#: AKModel/availability/models.py:309
 msgid "Availabilities"
 msgstr "Verfügbarkeiten"
 
@@ -242,7 +242,7 @@ msgstr ""
 "fürWünsche markieren, z.B. um während der Präsentation auf einem Touchscreen "
 "ausgefüllt zu werden?"
 
-#: AKModel/forms.py:198 AKModel/models.py:1510
+#: AKModel/forms.py:198 AKModel/models.py:1530
 msgid "Default Slots"
 msgstr "Standardslots"
 
@@ -289,7 +289,7 @@ msgstr "JSON-Daten"
 msgid "JSON data from the scheduling solver"
 msgstr "JSON-Daten, die der scheduling-solver produziert hat"
 
-#: AKModel/metaviews/admin.py:156 AKModel/models.py:129
+#: AKModel/metaviews/admin.py:156 AKModel/models.py:140
 msgid "Start"
 msgstr "Start"
 
@@ -314,67 +314,75 @@ msgstr "Aktivieren?"
 msgid "Finish"
 msgstr "Abschluss"
 
-#: AKModel/models.py:120 AKModel/models.py:723 AKModel/models.py:761
-#: AKModel/models.py:788 AKModel/models.py:807 AKModel/models.py:825
-#: AKModel/models.py:1015
+#: AKModel/models.py:24
+msgid "May not contain quotation marks"
+msgstr "Darf keine Anführungszeichen enthalten"
+
+#: AKModel/models.py:27
+msgid "Must contain at least one letter or digit"
+msgstr "Muss mindestens einen Buchstaben oder eine Ziffer enthalten"
+
+#: AKModel/models.py:131 AKModel/models.py:736 AKModel/models.py:774
+#: AKModel/models.py:801 AKModel/models.py:820 AKModel/models.py:838
+#: AKModel/models.py:1031
 msgid "Name"
 msgstr "Name"
 
-#: AKModel/models.py:121
+#: AKModel/models.py:132
 msgid "Name or iteration of the event"
 msgstr "Name oder Iteration des Events"
 
-#: AKModel/models.py:122
+#: AKModel/models.py:133
 msgid "Short Form"
 msgstr "Kurzer Name"
 
-#: AKModel/models.py:123
+#: AKModel/models.py:134
 msgid "Short name of letters/numbers/dots/dashes/underscores used in URLs."
 msgstr ""
 "Kurzname bestehend aus Buchstaben, Nummern, Punkten und Unterstrichen zur "
 "Nutzung in URLs"
 
-#: AKModel/models.py:125
+#: AKModel/models.py:136
 msgid "Place"
 msgstr "Ort"
 
-#: AKModel/models.py:126
+#: AKModel/models.py:137
 msgid "City etc. the event takes place in"
 msgstr "Stadt o.ä. in der das Event stattfindet"
 
-#: AKModel/models.py:128
+#: AKModel/models.py:139
 msgid "Time Zone"
 msgstr "Zeitzone"
 
-#: AKModel/models.py:128
+#: AKModel/models.py:139
 msgid "Time Zone where this event takes place in"
 msgstr "Zeitzone in der das Event stattfindet"
 
-#: AKModel/models.py:129
+#: AKModel/models.py:140
 msgid "Time the event begins"
 msgstr "Zeit zu der das Event beginnt"
 
-#: AKModel/models.py:130
+#: AKModel/models.py:141
 msgid "End"
 msgstr "Ende"
 
-#: AKModel/models.py:130
+#: AKModel/models.py:141
 msgid "Time the event ends"
 msgstr "Zeit zu der das Event endet"
 
-#: AKModel/models.py:131
+#: AKModel/models.py:142
 msgid "Resolution Deadline"
 msgstr "Resolutionsdeadline"
 
-#: AKModel/models.py:132
+#: AKModel/models.py:143
 msgid "When should AKs with intention to submit a resolution be done?"
 msgstr "Wann sollen AKs mit Resolutionsabsicht stattgefunden haben?"
 
-#: AKModel/models.py:134
+#: AKModel/models.py:145
 msgid "Interest Window Start"
 msgstr "Beginn Interessensbekundung"
 
-#: AKModel/models.py:136
+#: AKModel/models.py:147
 msgid ""
 "Opening time for expression of interest. When left blank, no interest "
 "indication will be possible."
@@ -382,71 +390,71 @@ msgstr ""
 "Öffnungszeitpunkt für die Angabe von Interesse an AKs.Wenn das Feld leer "
 "bleibt, wird keine Abgabe von Interesse möglich sein."
 
-#: AKModel/models.py:138
+#: AKModel/models.py:150
 msgid "Interest Window End"
 msgstr "Ende Interessensbekundung"
 
-#: AKModel/models.py:139
+#: AKModel/models.py:151
 msgid "Closing time for expression of interest."
 msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs."
 
-#: AKModel/models.py:141
+#: AKModel/models.py:153
 msgid "Public event"
 msgstr "Öffentliches Event"
 
-#: AKModel/models.py:142
+#: AKModel/models.py:154
 msgid "Show this event on overview page."
 msgstr "Zeige dieses Event auf der Übersichtseite an"
 
-#: AKModel/models.py:144
+#: AKModel/models.py:156
 msgid "Active State"
 msgstr "Aktiver Status"
 
-#: AKModel/models.py:144
+#: AKModel/models.py:156
 msgid "Marks currently active events"
 msgstr "Markiert aktuell aktive Events"
 
-#: AKModel/models.py:145
+#: AKModel/models.py:157
 msgid "Plan Hidden"
 msgstr "Plan verborgen"
 
-#: AKModel/models.py:145
+#: AKModel/models.py:157
 msgid "Hides plan for non-staff users"
 msgstr "Verbirgt den Plan für Nutzer*innen ohne erweiterte Rechte"
 
-#: AKModel/models.py:147
+#: AKModel/models.py:159
 msgid "Plan published at"
 msgstr "Plan veröffentlicht am/um"
 
-#: AKModel/models.py:148
+#: AKModel/models.py:160
 msgid "Timestamp at which the plan was published"
 msgstr "Zeitpunkt, zu dem der Plan veröffentlicht wurde"
 
-#: AKModel/models.py:150
+#: AKModel/models.py:162
 msgid "Base URL"
 msgstr "URL-Prefix"
 
-#: AKModel/models.py:150
+#: AKModel/models.py:162
 msgid "Prefix for wiki link construction"
 msgstr "Prefix für die automatische Generierung von Wiki-Links"
 
-#: AKModel/models.py:151
+#: AKModel/models.py:163
 msgid "Wiki Export Template Name"
 msgstr "Wiki-Export Templatename"
 
-#: AKModel/models.py:152
+#: AKModel/models.py:164
 msgid "Default Slot Length"
 msgstr "Standardslotlänge"
 
-#: AKModel/models.py:153
+#: AKModel/models.py:165
 msgid "Default length in hours that is assumed for AKs in this event."
 msgstr "Standardlänge von Slots (in Stunden) für dieses Event"
 
-#: AKModel/models.py:154
+#: AKModel/models.py:166
 msgid "Export Slot Length"
 msgstr "Export-Slotlänge"
 
-#: AKModel/models.py:156
+#: AKModel/models.py:168
 msgid ""
 "Slot duration in hours that is used in the timeslot discretization, when "
 "this event is exported for the solver."
@@ -454,11 +462,11 @@ msgstr ""
 "Länge von Slots (in Stunden) in der Zeitslot-Diskretisierung beim JSON-"
 "Export dieses Events."
 
-#: AKModel/models.py:161
+#: AKModel/models.py:172
 msgid "Contact email address"
 msgstr "E-Mail Kontaktadresse"
 
-#: AKModel/models.py:162
+#: AKModel/models.py:173
 msgid ""
 "An email address that is displayed on every page and can be used for all "
 "kinds of questions"
@@ -466,16 +474,16 @@ msgstr ""
 "Eine Mailadresse die auf jeder Seite angezeigt wird und für alle Arten von "
 "Fragen genutzt werden kann"
 
-#: AKModel/models.py:167
+#: AKModel/models.py:178
 msgid "Events"
 msgstr "Events"
 
-#: AKModel/models.py:444
+#: AKModel/models.py:455
 #, python-brace-format
 msgid "AK {ak_name} is not assigned any timeslot by the solver"
 msgstr "Dem AK {ak_name} wurde vom Solver kein Zeitslot zugewiesen"
 
-#: AKModel/models.py:454
+#: AKModel/models.py:465
 #, python-brace-format
 msgid ""
 "Duration of AK {ak_name} assigned by solver ({solver_duration} hours) is "
@@ -485,7 +493,7 @@ msgstr ""
 "Stunden) ist kürzer als die aktuell vorgesehene Dauer des Slots "
 "({slot_duration} Stunden)"
 
-#: AKModel/models.py:468
+#: AKModel/models.py:479
 #, python-brace-format
 msgid ""
 "Fixed AK {ak_name} assigned by solver to room {solver_room} is fixed to room "
@@ -494,7 +502,7 @@ msgstr ""
 "Dem fix geplanten AK {ak_name} wurde vom Solver Raum {solver_room} "
 "zugewiesen, dabei ist der AK bereits fix in Raum {slot_room} eingeplant."
 
-#: AKModel/models.py:479
+#: AKModel/models.py:490
 #, python-brace-format
 msgid ""
 "Fixed AK {ak_name} assigned by solver to start at {solver_start} is fixed to "
@@ -503,71 +511,71 @@ msgstr ""
 "Dem fix geplanten AK {ak_name} wurde vom Solver die Startzeit {solver_start} "
 "zugewiesen, dabei ist der AK bereits für {slot_start} eingeplant."
 
-#: AKModel/models.py:649
+#: AKModel/models.py:660
 msgid "Nickname"
 msgstr "Spitzname"
 
-#: AKModel/models.py:649
+#: AKModel/models.py:662
 msgid "Name to identify an AK owner by"
 msgstr "Name, durch den eine AK-Leitung identifiziert wird"
 
-#: AKModel/models.py:650
+#: AKModel/models.py:663
 msgid "Slug"
 msgstr "Slug"
 
-#: AKModel/models.py:650
+#: AKModel/models.py:663
 msgid "Slug for URL generation"
 msgstr "Slug für URL-Generierung"
 
-#: AKModel/models.py:651
+#: AKModel/models.py:664
 msgid "Institution"
 msgstr "Instutution"
 
-#: AKModel/models.py:651
+#: AKModel/models.py:664
 msgid "Uni etc."
 msgstr "Universität o.ä."
 
-#: AKModel/models.py:652 AKModel/models.py:834
+#: AKModel/models.py:665 AKModel/models.py:849
 msgid "Web Link"
 msgstr "Internet Link"
 
-#: AKModel/models.py:652
+#: AKModel/models.py:665
 msgid "Link to Homepage"
 msgstr "Link zu Homepage oder Webseite"
 
-#: AKModel/models.py:658 AKModel/models.py:1334
+#: AKModel/models.py:671 AKModel/models.py:1353
 msgid "AK Owner"
 msgstr "AK-Leitung"
 
-#: AKModel/models.py:659
+#: AKModel/models.py:672
 msgid "AK Owners"
 msgstr "AK-Leitungen"
 
-#: AKModel/models.py:723
+#: AKModel/models.py:736
 msgid "Name of the AK Category"
 msgstr "Name der AK-Kategorie"
 
-#: AKModel/models.py:724 AKModel/models.py:762
+#: AKModel/models.py:737 AKModel/models.py:775
 msgid "Color"
 msgstr "Farbe"
 
-#: AKModel/models.py:724 AKModel/models.py:762
+#: AKModel/models.py:737 AKModel/models.py:775
 msgid "Color for displaying"
 msgstr "Farbe für die Anzeige"
 
-#: AKModel/models.py:725 AKModel/models.py:828
+#: AKModel/models.py:738 AKModel/models.py:843
 msgid "Description"
 msgstr "Beschreibung"
 
-#: AKModel/models.py:726
+#: AKModel/models.py:739
 msgid "Short description of this AK Category"
 msgstr "Beschreibung der AK-Kategorie"
 
-#: AKModel/models.py:727
+#: AKModel/models.py:740
 msgid "Present by default"
 msgstr "Defaultmäßig präsentieren"
 
-#: AKModel/models.py:728
+#: AKModel/models.py:741
 msgid ""
 "Present AKs of this category by default if AK owner did not specify whether "
 "this AK should be presented?"
@@ -575,152 +583,152 @@ msgstr ""
 "AKs dieser Kategorie standardmäßig vorstellen, wenn die Leitungen das für "
 "ihren AK nicht explizit spezifiziert haben?"
 
-#: AKModel/models.py:736
+#: AKModel/models.py:749
 msgid "AK Categories"
 msgstr "AK-Kategorien"
 
-#: AKModel/models.py:761
+#: AKModel/models.py:774
 msgid "Name of the AK Track"
 msgstr "Name des AK-Tracks"
 
-#: AKModel/models.py:768
+#: AKModel/models.py:781
 msgid "AK Track"
 msgstr "AK-Track"
 
-#: AKModel/models.py:769
+#: AKModel/models.py:782
 msgid "AK Tracks"
 msgstr "AK-Tracks"
 
-#: AKModel/models.py:788
+#: AKModel/models.py:801
 msgid "Name of the Requirement"
 msgstr "Name der Anforderung"
 
-#: AKModel/models.py:794 AKModel/models.py:1338
+#: AKModel/models.py:807 AKModel/models.py:1357
 msgid "AK Requirement"
 msgstr "AK-Anforderung"
 
-#: AKModel/models.py:795
+#: AKModel/models.py:808
 msgid "AK Requirements"
 msgstr "AK-Anforderungen"
 
-#: AKModel/models.py:807
+#: AKModel/models.py:820
 msgid "Name describing the type"
 msgstr "Name, der den Typ beschreibt"
 
-#: AKModel/models.py:813
+#: AKModel/models.py:826
 msgid "AK Type"
 msgstr "AK Typ"
 
-#: AKModel/models.py:814
+#: AKModel/models.py:827
 msgid "AK Types"
 msgstr "AK-Typen"
 
-#: AKModel/models.py:825
+#: AKModel/models.py:838
 msgid "Name of the AK"
 msgstr "Name des AKs"
 
-#: AKModel/models.py:826
+#: AKModel/models.py:840
 msgid "Short Name"
 msgstr "Kurzer Name"
 
-#: AKModel/models.py:827
+#: AKModel/models.py:842
 msgid "Name displayed in the schedule"
 msgstr "Name zur Anzeige im AK-Plan"
 
-#: AKModel/models.py:828
+#: AKModel/models.py:843
 msgid "Description of the AK"
 msgstr "Beschreibung des AKs"
 
-#: AKModel/models.py:830
+#: AKModel/models.py:845
 msgid "Owners"
 msgstr "Leitungen"
 
-#: AKModel/models.py:831
+#: AKModel/models.py:846
 msgid "Those organizing the AK"
 msgstr "Menschen, die den AK organisieren und halten"
 
-#: AKModel/models.py:834
+#: AKModel/models.py:849
 msgid "Link to wiki page"
 msgstr "Link zur Wiki Seite"
 
-#: AKModel/models.py:835
+#: AKModel/models.py:850
 msgid "Protocol Link"
 msgstr "Protokolllink"
 
-#: AKModel/models.py:835
+#: AKModel/models.py:850
 msgid "Link to protocol"
 msgstr "Link zum Protokoll"
 
-#: AKModel/models.py:837
+#: AKModel/models.py:852
 msgid "Category"
 msgstr "Kategorie"
 
-#: AKModel/models.py:838
+#: AKModel/models.py:853
 msgid "Category of the AK"
 msgstr "Kategorie des AKs"
 
-#: AKModel/models.py:839 AKModel/models.py:904
+#: AKModel/models.py:854
 msgid "Types"
 msgstr "Typen"
 
-#: AKModel/models.py:840
+#: AKModel/models.py:855
 msgid "This AK is"
 msgstr "Dieser AK ist"
 
-#: AKModel/models.py:841
+#: AKModel/models.py:856
 msgid "Track"
 msgstr "Track"
 
-#: AKModel/models.py:842
+#: AKModel/models.py:857
 msgid "Track the AK belongs to"
 msgstr "Track zu dem der AK gehört"
 
-#: AKModel/models.py:844
+#: AKModel/models.py:859
 msgid "Resolution Intention"
 msgstr "Resolutionsabsicht"
 
-#: AKModel/models.py:845
+#: AKModel/models.py:860
 msgid "Intends to submit a resolution"
 msgstr "Beabsichtigt eine Resolution einzureichen"
 
-#: AKModel/models.py:846
+#: AKModel/models.py:861
 msgid "Present this AK"
 msgstr "AK präsentieren"
 
-#: AKModel/models.py:847
+#: AKModel/models.py:862
 msgid "Present results of this AK"
 msgstr "Die Ergebnisse dieses AKs vorstellen"
 
-#: AKModel/models.py:849 AKModel/models.py:902 AKModel/views/status.py:175
+#: AKModel/models.py:864 AKModel/views/status.py:175
 msgid "Requirements"
 msgstr "Anforderungen"
 
-#: AKModel/models.py:850
+#: AKModel/models.py:865
 msgid "AK's Requirements"
 msgstr "Anforderungen des AKs"
 
-#: AKModel/models.py:852
+#: AKModel/models.py:867
 msgid "Conflicting AKs"
 msgstr "AK-Konflikte"
 
-#: AKModel/models.py:853
+#: AKModel/models.py:868
 msgid "AKs that conflict and thus must not take place at the same time"
 msgstr ""
 "AKs, die Konflikte haben und deshalb nicht gleichzeitig stattfinden dürfen"
 
-#: AKModel/models.py:854
+#: AKModel/models.py:869
 msgid "Prerequisite AKs"
 msgstr "Vorausgesetzte AKs"
 
-#: AKModel/models.py:855
+#: AKModel/models.py:870
 msgid "AKs that should precede this AK in the schedule"
 msgstr "AKs die im AK-Plan vor diesem AK stattfinden müssen"
 
-#: AKModel/models.py:857
+#: AKModel/models.py:872
 msgid "Organizational Notes"
 msgstr "Notizen zur Organisation"
 
-#: AKModel/models.py:858
+#: AKModel/models.py:873
 msgid ""
 "Notes to organizers. These are public. For private notes, please use the "
 "button for private messages on the detail page of this AK (after creation/"
@@ -730,303 +738,295 @@ msgstr ""
 "Anmerkungen bitte den Button für Direktnachrichten verwenden (nach dem "
 "Anlegen/Bearbeiten)."
 
-#: AKModel/models.py:861 AKModel/models.py:900
+#: AKModel/models.py:876
 msgid "Interest"
 msgstr "Interesse"
 
-#: AKModel/models.py:861
+#: AKModel/models.py:876
 msgid "Expected number of people"
 msgstr "Erwartete Personenzahl"
 
-#: AKModel/models.py:862
+#: AKModel/models.py:877
 msgid "Interest Counter"
 msgstr "Interessenszähler"
 
-#: AKModel/models.py:863
+#: AKModel/models.py:878
 msgid "People who have indicated interest online"
 msgstr "Anzahl Personen, die online Interesse bekundet haben"
 
-#: AKModel/models.py:868
+#: AKModel/models.py:883
 msgid "Export?"
 msgstr "Export?"
 
-#: AKModel/models.py:869
+#: AKModel/models.py:884
 msgid "Include AK in wiki export?"
 msgstr "AK bei Wiki-Export berücksichtigen?"
 
-#: AKModel/models.py:919
-msgid "Conflicts"
-msgstr "Konflikte"
-
-#: AKModel/models.py:922
-msgid "Prerequisites"
-msgstr "Voraussetzungen"
-
-#: AKModel/models.py:1015
+#: AKModel/models.py:1031
 msgid "Name or number of the room"
 msgstr "Name oder Nummer des Raums"
 
-#: AKModel/models.py:1016
+#: AKModel/models.py:1032
 msgid "Location"
 msgstr "Ort"
 
-#: AKModel/models.py:1017
+#: AKModel/models.py:1033
 msgid "Name or number of the location"
 msgstr "Name oder Nummer des Ortes"
 
-#: AKModel/models.py:1018
+#: AKModel/models.py:1034
 msgid "Capacity"
 msgstr "Kapazität"
 
-#: AKModel/models.py:1019
+#: AKModel/models.py:1035
 msgid "Maximum number of people (-1 for unlimited)."
 msgstr "Maximale Personenzahl (-1 wenn unbeschränkt)."
 
-#: AKModel/models.py:1020
+#: AKModel/models.py:1036
 msgid "Properties"
 msgstr "Eigenschaften"
 
-#: AKModel/models.py:1021
+#: AKModel/models.py:1037
 msgid "AK requirements fulfilled by the room"
 msgstr "AK-Anforderungen, die dieser Raum erfüllt"
 
-#: AKModel/models.py:1028 AKModel/views/status.py:59
+#: AKModel/models.py:1044 AKModel/views/status.py:59
 msgid "Rooms"
 msgstr "Räume"
 
-#: AKModel/models.py:1089
+#: AKModel/models.py:1105
 msgid "AK being mapped"
 msgstr "AK, der zugeordnet wird"
 
-#: AKModel/models.py:1091
+#: AKModel/models.py:1107
 msgid "Room the AK will take place in"
 msgstr "Raum in dem der AK stattfindet"
 
-#: AKModel/models.py:1092 AKModel/models.py:1513
+#: AKModel/models.py:1108 AKModel/models.py:1533
 msgid "Slot Begin"
 msgstr "Beginn des Slots"
 
-#: AKModel/models.py:1092 AKModel/models.py:1513
+#: AKModel/models.py:1108 AKModel/models.py:1533
 msgid "Time and date the slot begins"
 msgstr "Zeit und Datum zu der der AK beginnt"
 
-#: AKModel/models.py:1094
+#: AKModel/models.py:1110
 msgid "Duration"
 msgstr "Dauer"
 
-#: AKModel/models.py:1095
+#: AKModel/models.py:1111
 msgid "Length in hours"
 msgstr "Länge in Stunden"
 
-#: AKModel/models.py:1097
+#: AKModel/models.py:1113
 msgid "Scheduling fixed"
 msgstr "Planung fix"
 
-#: AKModel/models.py:1098
+#: AKModel/models.py:1114
 msgid "Length and time of this AK should not be changed"
 msgstr "Dauer und Zeit dieses AKs sollten nicht verändert werden"
 
-#: AKModel/models.py:1103
+#: AKModel/models.py:1119
 msgid "Last update"
 msgstr "Letzte Aktualisierung"
 
-#: AKModel/models.py:1106
+#: AKModel/models.py:1122
 msgid "AK Slot"
 msgstr "AK-Slot"
 
-#: AKModel/models.py:1107 AKModel/models.py:1331 AKModel/models.py:1366
+#: AKModel/models.py:1123 AKModel/models.py:1350
 msgid "AK Slots"
 msgstr "AK-Slot"
 
-#: AKModel/models.py:1129 AKModel/models.py:1138
+#: AKModel/models.py:1145 AKModel/models.py:1154
 msgid "Not scheduled yet"
 msgstr "Noch nicht geplant"
 
-#: AKModel/models.py:1264
+#: AKModel/models.py:1282
 msgid "AK this message belongs to"
 msgstr "AK zu dem die Nachricht gehört"
 
-#: AKModel/models.py:1265
+#: AKModel/models.py:1283
 msgid "Message text"
 msgstr "Nachrichtentext"
 
-#: AKModel/models.py:1266
+#: AKModel/models.py:1284
 msgid "Message to the organizers. This is not publicly visible."
 msgstr ""
 "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar."
 
-#: AKModel/models.py:1270
+#: AKModel/models.py:1288
 msgid "Resolved"
 msgstr "Erledigt"
 
-#: AKModel/models.py:1271
+#: AKModel/models.py:1289
 msgid "This message has been resolved (no further action needed)"
 msgstr ""
 "Diese Nachricht wurde vollständig bearbeitet (keine weiteren Aktionen "
 "notwendig)"
 
-#: AKModel/models.py:1274
+#: AKModel/models.py:1292
 msgid "AK Orga Message"
 msgstr "AK-Organachricht"
 
-#: AKModel/models.py:1275
+#: AKModel/models.py:1293
 msgid "AK Orga Messages"
 msgstr "AK-Organachrichten"
 
-#: AKModel/models.py:1292
+#: AKModel/models.py:1311
 msgid "Constraint Violation"
 msgstr "Constraintverletzung"
 
-#: AKModel/models.py:1293
+#: AKModel/models.py:1312
 msgid "Constraint Violations"
 msgstr "Constraintverletzungen"
 
-#: AKModel/models.py:1300
+#: AKModel/models.py:1319
 msgid "Owner has two parallel slots"
 msgstr "Leitung hat zwei Slots parallel"
 
-#: AKModel/models.py:1301
+#: AKModel/models.py:1320
 msgid "AK Slot was scheduled outside the AK's availabilities"
 msgstr "AK Slot wurde außerhalb der Verfügbarkeit des AKs platziert"
 
-#: AKModel/models.py:1302
+#: AKModel/models.py:1321
 msgid "Room has two AK slots scheduled at the same time"
 msgstr "Raum hat zwei AK Slots gleichzeitig"
 
-#: AKModel/models.py:1303
+#: AKModel/models.py:1322
 msgid "Room does not satisfy the requirement of the scheduled AK"
 msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht"
 
-#: AKModel/models.py:1304
+#: AKModel/models.py:1323
 msgid "AK Slot is scheduled at the same time as an AK listed as a conflict"
 msgstr ""
 "AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert"
 
-#: AKModel/models.py:1305
+#: AKModel/models.py:1324
 msgid "AK Slot is scheduled before an AK listed as a prerequisite"
 msgstr "AK Slot wurde vor einem als Voraussetzung gelisteten AK platziert"
 
-#: AKModel/models.py:1307
+#: AKModel/models.py:1326
 msgid ""
 "AK Slot for AK with intention to submit a resolution is scheduled after "
 "resolution deadline"
 msgstr ""
 "AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert"
 
-#: AKModel/models.py:1308
+#: AKModel/models.py:1327
 msgid "AK Slot in a category is outside that categories availabilities"
 msgstr "AK Slot wurde außerhalb der Verfügbarkeiten seiner Kategorie"
 
-#: AKModel/models.py:1309
+#: AKModel/models.py:1328
 msgid "Two AK Slots for the same AK scheduled at the same time"
 msgstr "Zwei AK Slots eines AKs wurden zur selben Zeit platziert"
 
-#: AKModel/models.py:1310
+#: AKModel/models.py:1329
 msgid "Room does not have enough space for interest in scheduled AK Slot"
 msgstr "Room hat nicht genug Platz für das Interesse am geplanten AK-Slot"
 
-#: AKModel/models.py:1311
+#: AKModel/models.py:1330
 msgid "AK Slot is scheduled outside the event's availabilities"
 msgstr "AK Slot wurde außerhalb der Verfügbarkeit des Events platziert"
 
-#: AKModel/models.py:1317
+#: AKModel/models.py:1336
 msgid "Warning"
 msgstr "Warnung"
 
-#: AKModel/models.py:1318
+#: AKModel/models.py:1337
 msgid "Violation"
 msgstr "Verletzung"
 
-#: AKModel/models.py:1320
+#: AKModel/models.py:1339
 msgid "Type"
 msgstr "Art"
 
-#: AKModel/models.py:1321
+#: AKModel/models.py:1340
 msgid "Type of violation, i.e. what kind of constraint was violated"
 msgstr "Art der Verletzung, gibt an welche Art Constraint verletzt wurde"
 
-#: AKModel/models.py:1322
+#: AKModel/models.py:1341
 msgid "Level"
 msgstr "Level"
 
-#: AKModel/models.py:1323
+#: AKModel/models.py:1342
 msgid "Severity level of the violation"
 msgstr "Schweregrad der Verletzung"
 
-#: AKModel/models.py:1330
+#: AKModel/models.py:1349
 msgid "AK(s) belonging to this constraint"
 msgstr "AK(s), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:1332
+#: AKModel/models.py:1351
 msgid "AK Slot(s) belonging to this constraint"
 msgstr "AK Slot(s), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:1334
+#: AKModel/models.py:1353
 msgid "AK Owner belonging to this constraint"
 msgstr "AK Leitung(en), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:1336
+#: AKModel/models.py:1355
 msgid "Room belonging to this constraint"
 msgstr "Raum, der zu diesem Constraint gehört"
 
-#: AKModel/models.py:1339
+#: AKModel/models.py:1358
 msgid "AK Requirement belonging to this constraint"
 msgstr "AK Anforderung, die zu diesem Constraint gehört"
 
-#: AKModel/models.py:1341
+#: AKModel/models.py:1360
 msgid "AK Category belonging to this constraint"
 msgstr "AK Kategorie, di zu diesem Constraint gehört"
 
-#: AKModel/models.py:1343
+#: AKModel/models.py:1362
 msgid "Comment"
 msgstr "Kommentar"
 
-#: AKModel/models.py:1343
+#: AKModel/models.py:1362
 msgid "Comment or further details for this violation"
 msgstr "Kommentar oder weitere Details zu dieser Vereletzung"
 
-#: AKModel/models.py:1346
+#: AKModel/models.py:1365
 msgid "Timestamp"
 msgstr "Timestamp"
 
-#: AKModel/models.py:1346
+#: AKModel/models.py:1365
 msgid "Time of creation"
 msgstr "Zeitpunkt der ERstellung"
 
-#: AKModel/models.py:1347
+#: AKModel/models.py:1366
 msgid "Manually Resolved"
 msgstr "Manuell behoben"
 
-#: AKModel/models.py:1348
+#: AKModel/models.py:1367
 msgid "Mark this violation manually as resolved"
 msgstr "Markiere diese Verletzung manuell als behoben"
 
-#: AKModel/models.py:1375 AKModel/templates/admin/AKModel/aks_by_user.html:22
+#: AKModel/models.py:1394 AKModel/templates/admin/AKModel/aks_by_user.html:22
 #: AKModel/templates/admin/AKModel/requirements_overview.html:27
 msgid "Details"
 msgstr "Details"
 
-#: AKModel/models.py:1509
+#: AKModel/models.py:1529
 msgid "Default Slot"
 msgstr "Standardslot"
 
-#: AKModel/models.py:1514
+#: AKModel/models.py:1534
 msgid "Slot End"
 msgstr "Ende des Slots"
 
-#: AKModel/models.py:1514
+#: AKModel/models.py:1534
 msgid "Time and date the slot ends"
 msgstr "Zeit und Datum zu der der Slot endet"
 
-#: AKModel/models.py:1519
+#: AKModel/models.py:1539
 msgid "Primary categories"
 msgstr "Primäre Kategorien"
 
-#: AKModel/models.py:1520
+#: AKModel/models.py:1541
 msgid "Categories that should be assigned to this slot primarily"
 msgstr "Kategorieren, die diesem Slot primär zugewiesen werden sollen"
 
-#: AKModel/site.py:13 AKModel/site.py:14
+#: AKModel/site.py:14
 msgid "Administration"
 msgstr "Verwaltung"
 
@@ -1241,35 +1241,35 @@ msgstr "AK-CSV-Export"
 msgid "AK JSON Export"
 msgstr "AK-JSON-Export"
 
-#: AKModel/views/ak.py:72
+#: AKModel/views/ak.py:69
 msgid "AK Wiki Export"
 msgstr "AK-Wiki-Export"
 
-#: AKModel/views/ak.py:83 AKModel/views/manage.py:55
+#: AKModel/views/ak.py:80 AKModel/views/manage.py:55
 msgid "Wishes"
 msgstr "Wünsche"
 
-#: AKModel/views/ak.py:95
+#: AKModel/views/ak.py:92
 msgid "Delete AK Orga Messages"
 msgstr "AK-Organachrichten löschen"
 
-#: AKModel/views/ak.py:113
+#: AKModel/views/ak.py:110
 msgid "AK Orga Messages successfully deleted"
 msgstr "AK-Organachrichten erfolgreich gelöscht"
 
-#: AKModel/views/ak.py:125
+#: AKModel/views/ak.py:122
 msgid "Interest of the following AKs will be set to not filled (-1):"
 msgstr "Interesse an den folgenden AKs wird auf nicht ausgefüllt (-1) gesetzt:"
 
-#: AKModel/views/ak.py:126
+#: AKModel/views/ak.py:123
 msgid "Reset of interest in AKs successful."
 msgstr "Interesse an AKs erfolgreich zurückgesetzt."
 
-#: AKModel/views/ak.py:140
+#: AKModel/views/ak.py:137
 msgid "Interest counter of the following AKs will be set to 0:"
 msgstr "Interessensbekundungszähler der folgenden AKs wird auf 0 gesetzt:"
 
-#: AKModel/views/ak.py:141
+#: AKModel/views/ak.py:138
 msgid "AKs' interest counters set back to 0."
 msgstr "Interessenszähler der AKs zurückgesetzt"
 
@@ -1455,6 +1455,12 @@ msgstr "Zu Anforderungen gehörige AKs anzeigen"
 msgid "Event Status"
 msgstr "Eventstatus"
 
+#~ msgid "Conflicts"
+#~ msgstr "Konflikte"
+
+#~ msgid "Prerequisites"
+#~ msgstr "Voraussetzungen"
+
 #~ msgid "Opening time for expression of interest."
 #~ msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs."
 
diff --git a/AKModel/migrations/0063_field_validators.py b/AKModel/migrations/0063_field_validators.py
new file mode 100644
index 0000000000000000000000000000000000000000..347eba289327dd8dc7b8c921f385626c2c725688
--- /dev/null
+++ b/AKModel/migrations/0063_field_validators.py
@@ -0,0 +1,39 @@
+# Generated by Django 4.2.13 on 2025-03-03 19:59
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('AKModel', '0062_interest_no_history'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='ak',
+            name='name',
+            field=models.CharField(help_text='Name of the AK', max_length=256, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Name'),
+        ),
+        migrations.AlterField(
+            model_name='ak',
+            name='short_name',
+            field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+')], verbose_name='Short Name'),
+        ),
+        migrations.AlterField(
+            model_name='akowner',
+            name='name',
+            field=models.CharField(help_text='Name to identify an AK owner by', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Nickname'),
+        ),
+        migrations.AlterField(
+            model_name='historicalak',
+            name='name',
+            field=models.CharField(help_text='Name of the AK', max_length=256, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Name'),
+        ),
+        migrations.AlterField(
+            model_name='historicalak',
+            name='short_name',
+            field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+')], verbose_name='Short Name'),
+        ),
+    ]
diff --git a/AKModel/migrations/0064_merge_20250304_1416.py b/AKModel/migrations/0064_merge_20250304_1416.py
new file mode 100644
index 0000000000000000000000000000000000000000..456a64455182a03bd08b5c030bed1284adaccc67
--- /dev/null
+++ b/AKModel/migrations/0064_merge_20250304_1416.py
@@ -0,0 +1,14 @@
+# Generated by Django 5.1.6 on 2025-03-04 14:16
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('AKModel', '0063_field_validators'),
+        ('AKModel', '0063_merge_0061_event_export_slot_0062_interest_no_history'),
+    ]
+
+    operations = [
+    ]
diff --git a/AKModel/models.py b/AKModel/models.py
index e6271580dd69e8167a54f31393dd7e8503d298a3..9d7b6c2e15dc332fec9472a0553878670a7288a2 100644
--- a/AKModel/models.py
+++ b/AKModel/models.py
@@ -4,10 +4,11 @@ import json
 import math
 from dataclasses import dataclass
 from datetime import datetime, timedelta
-from typing import Any, Iterable, Generator
+from typing import Any, Generator, Iterable
 
-from django.db import models, transaction
 from django.apps import apps
+from django.core.validators import RegexValidator
+from django.db import models, transaction
 from django.db.models import Count
 from django.urls import reverse_lazy
 from django.utils import timezone
@@ -16,6 +17,15 @@ from django.utils.translation import gettext_lazy as _
 from simple_history.models import HistoricalRecords
 from timezone_field import TimeZoneField
 
+# Custom validators to be used for some of the fields
+# Prevent inclusion of the quotation marks ' " ´ `
+# This may be necessary to prevent javascript issues
+no_quotation_marks_validator = RegexValidator(regex=r"['\"´`]+", inverse_match=True,
+                                              message=_('May not contain quotation marks'))
+# Enforce that the field contains of at least one letter or digit (and not just special characters
+# This prevents issues when autogenerating slugs from that field
+slugable_validator = RegexValidator(regex=r"[\w\s]+", message=_('Must contain at least one letter or digit'))
+
 
 @dataclass
 class OptimizerTimeslot:
@@ -41,17 +51,18 @@ class OptimizerTimeslot:
         avail = self.avail.merge_with(other.avail)
         constraints = self.constraints.union(other.constraints)
         return OptimizerTimeslot(
-            avail=avail, idx=self.idx, constraints=constraints
+                avail=avail, idx=self.idx, constraints=constraints
         )
 
     def __repr__(self) -> str:
         return f"({self.avail.simplified}, {self.idx}, {self.constraints})"
 
+
 TimeslotBlock = list[OptimizerTimeslot]
 
 
 def merge_blocks(
-    blocks: Iterable[TimeslotBlock]
+        blocks: Iterable[TimeslotBlock]
 ) -> Iterable[TimeslotBlock]:
     """Merge iterable of blocks together.
 
@@ -73,8 +84,8 @@ def merge_blocks(
 
     # sort timeslots according to start
     timeslots = sorted(
-        timeslot_chain,
-        key=lambda slot: slot.avail.start
+            timeslot_chain,
+            key=lambda slot: slot.avail.start
     )
 
     if not timeslots:
@@ -87,8 +98,8 @@ def merge_blocks(
     for slot in timeslots:
         if current_block and slot.avail.overlaps(current_block[-1].avail, strict=True):
             if (
-                slot.avail.start == current_block[-1].avail.start
-                and slot.avail.end == current_block[-1].avail.end
+                    slot.avail.start == current_block[-1].avail.start
+                    and slot.avail.end == current_block[-1].avail.end
             ):
                 # the same timeslot -> merge
                 current_block[-1] = current_block[-1].merge(slot)
@@ -96,8 +107,8 @@ def merge_blocks(
                 # partial overlap of interiors -> not supported
                 # TODO: Show comprehensive message in production
                 raise ValueError(
-                    "Partially overlapping timeslots are not supported!"
-                    f" ({current_block[-1].avail.simplified}, {slot.avail.simplified})"
+                        "Partially overlapping timeslots are not supported!"
+                        f" ({current_block[-1].avail.simplified}, {slot.avail.simplified})"
                 )
         elif not current_block or slot.avail.overlaps(current_block[-1].avail, strict=False):
             # only endpoints in intersection -> same block
@@ -132,8 +143,9 @@ class Event(models.Model):
                                          help_text=_('When should AKs with intention to submit a resolution be done?'))
 
     interest_start = models.DateTimeField(verbose_name=_('Interest Window Start'), blank=True, null=True,
-              help_text=
-              _('Opening time for expression of interest. When left blank, no interest indication will be possible.'))
+                                          help_text=
+                                          _('Opening time for expression of interest. When left blank, no interest '
+                                            'indication will be possible.'))
 
     interest_end = models.DateTimeField(verbose_name=_('Interest Window End'), blank=True, null=True,
                                         help_text=_('Closing time for expression of interest.'))
@@ -145,22 +157,21 @@ class Event(models.Model):
     plan_hidden = models.BooleanField(verbose_name=_('Plan Hidden'), help_text=_('Hides plan for non-staff users'),
                                       default=True)
     plan_published_at = models.DateTimeField(verbose_name=_('Plan published at'), blank=True, null=True,
-                                         help_text=_('Timestamp at which the plan was published'))
+                                             help_text=_('Timestamp at which the plan was published'))
 
     base_url = models.URLField(verbose_name=_("Base URL"), help_text=_("Prefix for wiki link construction"), blank=True)
     wiki_export_template_name = models.CharField(verbose_name=_("Wiki Export Template Name"), blank=True, max_length=50)
     default_slot = models.DecimalField(max_digits=4, decimal_places=2, default=2, verbose_name=_('Default Slot Length'),
                                        help_text=_('Default length in hours that is assumed for AKs in this event.'))
     export_slot = models.DecimalField(max_digits=4, decimal_places=2, default=1, verbose_name=_('Export Slot Length'),
-                                        help_text=_(
-                                            'Slot duration in hours that is used in the timeslot discretization, '
-                                            'when this event is exported for the solver.'
-                                        ))
-
+                                      help_text=_(
+                                              'Slot duration in hours that is used in the timeslot discretization, '
+                                              'when this event is exported for the solver.'
+                                      ))
 
     contact_email = models.EmailField(verbose_name=_("Contact email address"), blank=True,
-                                        help_text=_("An email address that is displayed on every page "
-                                                    "and can be used for all kinds of questions"))
+                                      help_text=_("An email address that is displayed on every page "
+                                                  "and can be used for all kinds of questions"))
 
     class Meta:
         verbose_name = _('Event')
@@ -191,7 +202,7 @@ class Event(models.Model):
         event = Event.objects.filter(active=True).order_by('start').first()
         # No active event? Return the next event taking place
         if event is None:
-            event = Event.objects.order_by('start').filter(start__gt=datetime.now()).first()
+            event = Event.objects.order_by('start').filter(start__gt=datetime.now().astimezone()).first()
         return event
 
     def get_categories_with_aks(self, wishes_seperately=False,
@@ -269,13 +280,13 @@ class Event(models.Model):
                 )
 
     def _generate_slots_from_block(
-        self,
-        start: datetime,
-        end: datetime,
-        slot_duration: timedelta,
-        *,
-        slot_index: int = 0,
-        constraints: set[str] | None = None,
+            self,
+            start: datetime,
+            end: datetime,
+            slot_duration: timedelta,
+            *,
+            slot_index: int = 0,
+            constraints: set[str] | None = None,
     ) -> Generator[TimeslotBlock, None, int]:
         """Discretize a time range into timeslots.
 
@@ -316,22 +327,22 @@ class Event(models.Model):
 
         while current_slot_start + slot_duration <= end:
             slot = Availability(
-                event=self,
-                start=current_slot_start,
-                end=current_slot_start + slot_duration,
+                    event=self,
+                    start=current_slot_start,
+                    end=current_slot_start + slot_duration,
             )
 
             if any((availability.contains(slot) for availability in room_availabilities)):
                 # no gap in a block
                 if (
-                    previous_slot_start is not None
-                    and previous_slot_start + slot_duration < current_slot_start
+                        previous_slot_start is not None
+                        and previous_slot_start + slot_duration < current_slot_start
                 ):
                     yield current_block
                     current_block = []
 
                 current_block.append(
-                    OptimizerTimeslot(avail=slot, idx=slot_index, constraints=constraints)
+                        OptimizerTimeslot(avail=slot, idx=slot_index, constraints=constraints)
                 )
                 previous_slot_start = current_slot_start
 
@@ -355,14 +366,14 @@ class Event(models.Model):
         :ytype: list of OptimizerTimeslot
         """
         all_category_constraints = AKCategory.create_category_constraints(
-            AKCategory.objects.filter(event=self).all()
+                AKCategory.objects.filter(event=self).all()
         )
 
         yield from self._generate_slots_from_block(
-            start=self.start,
-            end=self.end,
-            slot_duration=timedelta(hours=1.0 / slots_in_an_hour),
-            constraints=all_category_constraints,
+                start=self.start,
+                end=self.end,
+                slot_duration=timedelta(hours=1.0 / slots_in_an_hour),
+                constraints=all_category_constraints,
         )
 
     def default_time_slots(self, *, slots_in_an_hour: float) -> Iterable[TimeslotBlock]:
@@ -380,15 +391,15 @@ class Event(models.Model):
 
         for block_slot in DefaultSlot.objects.filter(event=self).order_by("start", "end"):
             category_constraints = AKCategory.create_category_constraints(
-                block_slot.primary_categories.all()
+                    block_slot.primary_categories.all()
             )
 
             slot_index = yield from self._generate_slots_from_block(
-                start=block_slot.start,
-                end=block_slot.end,
-                slot_duration=slot_duration,
-                slot_index=slot_index,
-                constraints=category_constraints,
+                    start=block_slot.start,
+                    end=block_slot.end,
+                    slot_duration=slot_duration,
+                    slot_index=slot_index,
+                    constraints=category_constraints,
             )
 
     def discretize_timeslots(self, *, slots_in_an_hour: float | None = None) -> Iterable[TimeslotBlock]:
@@ -441,7 +452,7 @@ class Event(models.Model):
 
             if not scheduled_slot["timeslot_ids"]:
                 raise ValueError(
-                    _("AK {ak_name} is not assigned any timeslot by the solver").format(ak_name=slot.ak.name)
+                        _("AK {ak_name} is not assigned any timeslot by the solver").format(ak_name=slot.ak.name)
                 )
 
             start_timeslot = timeslot_dict[min(scheduled_slot["timeslot_ids"])].avail
@@ -450,39 +461,39 @@ class Event(models.Model):
 
             if solver_duration + 2e-4 < slot.duration:
                 raise ValueError(
-                    _(
-                        "Duration of AK {ak_name} assigned by solver ({solver_duration} hours) "
-                        "is less than the duration required by the slot ({slot_duration} hours)"
-                    ).format(
-                        ak_name=slot.ak.name,
-                        solver_duration=solver_duration,
-                        slot_duration=slot.duration,
-                    )
+                        _(
+                                "Duration of AK {ak_name} assigned by solver ({solver_duration} hours) "
+                                "is less than the duration required by the slot ({slot_duration} hours)"
+                        ).format(
+                                ak_name=slot.ak.name,
+                                solver_duration=solver_duration,
+                                slot_duration=slot.duration,
+                        )
                 )
 
             if slot.fixed:
                 solver_room = Room.objects.get(id=int(scheduled_slot["room_id"]))
                 if slot.room != solver_room:
                     raise ValueError(
-                        _(
-                            "Fixed AK {ak_name} assigned by solver to room {solver_room} "
-                            "is fixed to room {slot_room}"
-                        ).format(
-                            ak_name=slot.ak.name,
-                            solver_room=solver_room.name,
-                            slot_room=slot.room.name,
-                        )
+                            _(
+                                    "Fixed AK {ak_name} assigned by solver to room {solver_room} "
+                                    "is fixed to room {slot_room}"
+                            ).format(
+                                    ak_name=slot.ak.name,
+                                    solver_room=solver_room.name,
+                                    slot_room=slot.room.name,
+                            )
                     )
                 if slot.start != start_timeslot.start:
                     raise ValueError(
-                        _(
-                            "Fixed AK {ak_name} assigned by solver to start at {solver_start} "
-                            "is fixed to start at {slot_start}"
-                        ).format(
-                            ak_name=slot.ak.name,
-                            solver_start=start_timeslot.start,
-                            slot_start=slot.start,
-                        )
+                            _(
+                                    "Fixed AK {ak_name} assigned by solver to start at {solver_start} "
+                                    "is fixed to start at {slot_start}"
+                            ).format(
+                                    ak_name=slot.ak.name,
+                                    solver_start=start_timeslot.start,
+                                    slot_start=slot.start,
+                            )
                     )
             else:
                 slot.room = Room.objects.get(id=int(scheduled_slot["room_id"]))
@@ -520,14 +531,14 @@ class Event(models.Model):
         def _test_add_constraint(slot: Availability, availabilities: list[Availability]) -> bool:
             """Test if object is not available for whole event and may happen during slot."""
             return (
-                _test_event_not_covered(availabilities) and slot.is_covered(availabilities)
+                    _test_event_not_covered(availabilities) and slot.is_covered(availabilities)
             )
 
         def _generate_time_constraints(
-            avail_label: str,
-            avail_dict: dict,
-            timeslot_avail: Availability,
-            prefix: str = "availability",
+                avail_label: str,
+                avail_dict: dict,
+                timeslot_avail: Availability,
+                prefix: str = "availability",
         ) -> list[str]:
             return [
                 f"{prefix}-{avail_label}-{pk}"
@@ -538,7 +549,7 @@ class Event(models.Model):
         timeslots = {
             "info": {"duration": float(self.export_slot)},
             "blocks": [],
-            }
+        }
 
         rooms = Room.objects.filter(event=self).order_by()
         slots = AKSlot.objects.filter(event=self).order_by()
@@ -589,17 +600,17 @@ class Event(models.Model):
 
                 # add fulfilled time constraints for all AKs that cannot happen during full event
                 time_constraints.extend(
-                    _generate_time_constraints("ak", ak_availabilities, timeslot.avail)
+                        _generate_time_constraints("ak", ak_availabilities, timeslot.avail)
                 )
 
                 # add fulfilled time constraints for all persons that are not available for full event
                 time_constraints.extend(
-                    _generate_time_constraints("person", person_availabilities, timeslot.avail)
+                        _generate_time_constraints("person", person_availabilities, timeslot.avail)
                 )
 
                 # add fulfilled time constraints for all rooms that are not available for full event
                 time_constraints.extend(
-                    _generate_time_constraints("room", room_availabilities, timeslot.avail)
+                        _generate_time_constraints("room", room_availabilities, timeslot.avail)
                 )
 
                 # add fulfilled time constraints for all AKSlots fixed to happen during timeslot
@@ -619,7 +630,7 @@ class Event(models.Model):
                         "end": timeslot.avail.end.astimezone(self.timezone).strftime("%Y-%m-%d %H:%M"),
                     },
                     "fulfilled_time_constraints": sorted(time_constraints),
-                    })
+                })
 
             timeslots["blocks"].append(current_block)
 
@@ -646,7 +657,9 @@ class Event(models.Model):
 class AKOwner(models.Model):
     """ An AKOwner describes the person organizing/holding an AK.
     """
-    name = models.CharField(max_length=64, verbose_name=_('Nickname'), help_text=_('Name to identify an AK owner by'))
+    name = models.CharField(max_length=64, verbose_name=_('Nickname'),
+                            validators=[no_quotation_marks_validator, slugable_validator],
+                            help_text=_('Name to identify an AK owner by'))
     slug = models.SlugField(max_length=64, blank=True, verbose_name=_('Slug'), help_text=_('Slug for URL generation'))
     institution = models.CharField(max_length=128, blank=True, verbose_name=_('Institution'), help_text=_('Uni etc.'))
     link = models.URLField(blank=True, verbose_name=_('Web Link'), help_text=_('Link to Homepage'))
@@ -725,8 +738,8 @@ class AKCategory(models.Model):
     description = models.TextField(blank=True, verbose_name=_("Description"),
                                    help_text=_("Short description of this AK Category"))
     present_by_default = models.BooleanField(blank=True, default=True, verbose_name=_("Present by default"),
-                                             help_text=_("Present AKs of this category by default "
-                                                 "if AK owner did not specify whether this AK should be presented?"))
+                                             help_text=_("Present AKs of this category by default if AK owner did not "
+                                                         "specify whether this AK should be presented?"))
 
     event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'),
                               help_text=_('Associated event'))
@@ -822,8 +835,10 @@ class AKType(models.Model):
 class AK(models.Model):
     """ An AK is a slot-based activity to be scheduled during an event.
     """
-    name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK'))
+    name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK'),
+                            validators=[no_quotation_marks_validator, slugable_validator])
     short_name = models.CharField(max_length=64, blank=True, verbose_name=_('Short Name'),
+                                  validators=[no_quotation_marks_validator],
                                   help_text=_('Name displayed in the schedule'))
     description = models.TextField(blank=True, verbose_name=_('Description'), help_text=_('Description of the AK'))
 
@@ -837,7 +852,7 @@ class AK(models.Model):
     category = models.ForeignKey(to=AKCategory, on_delete=models.PROTECT, verbose_name=_('Category'),
                                  help_text=_('Category of the AK'))
     types = models.ManyToManyField(to=AKType, blank=True, verbose_name=_('Types'),
-                                          help_text=_("This AK is"))
+                                   help_text=_("This AK is"))
     track = models.ForeignKey(to=AKTrack, blank=True, on_delete=models.SET_NULL, null=True, verbose_name=_('Track'),
                               help_text=_('Track the AK belongs to'))
 
@@ -855,8 +870,8 @@ class AK(models.Model):
                                            help_text=_('AKs that should precede this AK in the schedule'))
 
     notes = models.TextField(blank=True, verbose_name=_('Organizational Notes'), help_text=_(
-        'Notes to organizers. These are public. For private notes, please use the button for private messages '
-        'on the detail page of this AK (after creation/editing).'))
+            'Notes to organizers. These are public. For private notes, please use the button for private messages '
+            'on the detail page of this AK (after creation/editing).'))
 
     interest = models.IntegerField(default=-1, verbose_name=_('Interest'), help_text=_('Expected number of people'))
     interest_counter = models.IntegerField(default=0, verbose_name=_('Interest Counter'),
@@ -997,7 +1012,7 @@ class AK(models.Model):
             return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.event.slug, 'pk': self.id})
         return self.edit_url
 
-    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
+    def save(self, *args, force_insert=False, force_update=False, using=None, update_fields=None):
         # Auto-Generate Link if not set yet
         if self.link == "":
             link = self.event.base_url + self.name.replace(" ", "_")
@@ -1006,7 +1021,8 @@ class AK(models.Model):
             # Tell Django that we have updated the link field
             if update_fields is not None:
                 update_fields = {"link"}.union(update_fields)
-        super().save(force_insert, force_update, using, update_fields)
+        super().save(*args,
+                     force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
 
 
 class Room(models.Model):
@@ -1161,7 +1177,7 @@ class AKSlot(models.Model):
 
     def overlaps(self, other: "AKSlot"):
         """
-        Check wether two slots overlap
+        Check whether two slots overlap
 
         :param other: second slot to compare with
         :return: true if they overlap, false if not:
@@ -1169,13 +1185,14 @@ class AKSlot(models.Model):
         """
         return self.start < other.end <= self.end or self.start <= other.start < self.end
 
-    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
+    def save(self, *args, force_insert=False, force_update=False, using=None, update_fields=None):
         # Make sure duration is not longer than the event
         if update_fields is None or 'duration' in update_fields:
             event_duration = self.event.end - self.event.start
             event_duration_hours = event_duration.days * 24 + event_duration.seconds // 3600
             self.duration = min(self.duration, event_duration_hours)
-        super().save(force_insert, force_update, using, update_fields)
+        super().save(*args,
+                     force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
 
     def as_json_dict(self) -> dict[str, Any]:
         """Return a json representation of the AK object of this slot.
@@ -1217,8 +1234,8 @@ class AKSlot(models.Model):
             "properties": {
                 "conflicts":
                     sorted(
-                        [conflict.pk for conflict in conflict_slots.all()]
-                      + [second_slot.pk for second_slot in other_ak_slots.all()]
+                            [conflict.pk for conflict in conflict_slots.all()]
+                            + [second_slot.pk for second_slot in other_ak_slots.all()]
                     ),
                 "dependencies": sorted([dep.pk for dep in dependency_slots.all()]),
             },
@@ -1234,8 +1251,8 @@ class AKSlot(models.Model):
                 "duration_in_hours": float(self.duration),
                 "django_ak_id": self.ak.pk,
                 "types": list(self.ak.types.values_list("name", flat=True).order_by()),
-                },
-            }
+            },
+        }
 
         data["time_constraints"].extend(ak_time_constraints)
         for owner in self.ak.owners.all():
@@ -1256,6 +1273,7 @@ class AKSlot(models.Model):
 
         return data
 
+
 class AKOrgaMessage(models.Model):
     """
     Model representing confidential messages to the organizers/scheduling people, belonging to a certain AK
@@ -1288,6 +1306,7 @@ class ConstraintViolation(models.Model):
     Depending on the type, different fields (references to other models) will be filled. Each violation should always
     be related to an event and at least on other instance of a causing entity
     """
+
     class Meta:
         verbose_name = _('Constraint Violation')
         verbose_name_plural = _('Constraint Violations')
@@ -1304,7 +1323,7 @@ class ConstraintViolation(models.Model):
         AK_CONFLICT_COLLISION = 'acc', _('AK Slot is scheduled at the same time as an AK listed as a conflict')
         AK_BEFORE_PREREQUISITE = 'abp', _('AK Slot is scheduled before an AK listed as a prerequisite')
         AK_AFTER_RESODEADLINE = 'aar', _(
-            'AK Slot for AK with intention to submit a resolution is scheduled after resolution deadline')
+                'AK Slot for AK with intention to submit a resolution is scheduled after resolution deadline')
         AK_CATEGORY_MISMATCH = 'acm', _('AK Slot in a category is outside that categories availabilities')
         AK_SLOT_COLLISION = 'asc', _('Two AK Slots for the same AK scheduled at the same time')
         ROOM_CAPACITY_EXCEEDED = 'rce', _('Room does not have enough space for interest in scheduled AK Slot')
@@ -1505,6 +1524,7 @@ class DefaultSlot(models.Model):
     Model representing a default slot,
     i.e., a prefered slot to use for typical AKs in the schedule to guarantee enough breaks etc.
     """
+
     class Meta:
         verbose_name = _('Default Slot')
         verbose_name_plural = _('Default Slots')
@@ -1517,7 +1537,8 @@ class DefaultSlot(models.Model):
                               help_text=_('Associated event'))
 
     primary_categories = models.ManyToManyField(to=AKCategory, verbose_name=_('Primary categories'), blank=True,
-                                            help_text=_('Categories that should be assigned to this slot primarily'))
+                                                help_text=_(
+                                                        'Categories that should be assigned to this slot primarily'))
 
     @property
     def start_simplified(self) -> str:
diff --git a/AKPlan/views.py b/AKPlan/views.py
index 4123256e0ceb18c0da87526deaea1a0b46b91b39..a3c240a9a46a32937307f8a7381c14aa3b076c4f 100644
--- a/AKPlan/views.py
+++ b/AKPlan/views.py
@@ -1,13 +1,12 @@
-from datetime import timedelta
+from datetime import datetime, timedelta
 
 from django.conf import settings
 from django.shortcuts import redirect
 from django.urls import reverse_lazy
-from django.utils.datetime_safe import datetime
-from django.views.generic import ListView, DetailView
+from django.views.generic import DetailView, ListView
 
-from AKModel.models import AKSlot, Room, AKTrack
 from AKModel.metaviews.admin import FilterByEventSlugMixin
+from AKModel.models import AKSlot, AKTrack, Room
 
 
 class PlanIndexView(FilterByEventSlugMixin, ListView):
@@ -152,7 +151,7 @@ class PlanTrackView(FilterByEventSlugMixin, DetailView):
         context = super().get_context_data(object_list=object_list, **kwargs)
         # Restrict AKSlot list to given track
         # while joining AK, room and category information to reduce the amount of necessary SQL queries
-        context["slots"] = AKSlot.objects.\
-            filter(event=self.event, ak__track=context['track']).\
+        context["slots"] = AKSlot.objects. \
+            filter(event=self.event, ak__track=context['track']). \
             select_related('ak', 'room', 'ak__category')
         return context
diff --git a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po
index a2fb73ef747f3bc8e7aef7e38ddaef1d28275acd..3944e8722fe004177ef48f6119fa1bd5dd6e38d3 100644
--- a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po
+++ b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-02-27 15:13+0000\n"
+"POT-Creation-Date: 2025-03-04 14:49+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -107,7 +107,6 @@ msgid "Event Status"
 msgstr "Event-Status"
 
 #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:113
-#: AKScheduling/views.py:50
 msgid "Scheduling"
 msgstr "Scheduling"
 
@@ -240,7 +239,6 @@ msgstr[1] ""
 "        "
 
 #: AKScheduling/templates/admin/AKScheduling/unscheduled.html:7
-#: AKScheduling/views.py:25
 msgid "Unscheduled AK Slots"
 msgstr "Noch nicht geschedulte AK-Slots"
 
@@ -248,22 +246,10 @@ msgstr "Noch nicht geschedulte AK-Slots"
 msgid "Count"
 msgstr "Anzahl"
 
-#: AKScheduling/views.py:91
-msgid "Constraint violations for"
-msgstr "Constraintverletzungen für"
-
-#: AKScheduling/views.py:106
-msgid "AKs requiring special attention for"
-msgstr "AKs die besondere Aufmerksamkeit erfordern für"
-
 #: AKScheduling/views.py:152
 msgid "Interest updated"
 msgstr "Interesse aktualisiert"
 
-#: AKScheduling/views.py:166
-msgid "Enter interest"
-msgstr "Interesse eingeben"
-
 #: AKScheduling/views.py:210
 msgid "Wishes"
 msgstr "Wünsche"
@@ -319,6 +305,15 @@ msgstr "Standardverfügbarkeiten für {count} AKs angelegt"
 msgid "Constraint Violations"
 msgstr "Constraintverletzungen"
 
+#~ msgid "Constraint violations for"
+#~ msgstr "Constraintverletzungen für"
+
+#~ msgid "AKs requiring special attention for"
+#~ msgstr "AKs die besondere Aufmerksamkeit erfordern für"
+
+#~ msgid "Enter interest"
+#~ msgstr "Interesse eingeben"
+
 #~ msgid "Bitte AK auswählen"
 #~ msgstr "Please sel"
 
diff --git a/AKSubmission/api.py b/AKSubmission/api.py
index 39c3fd460a404735e66d690746c8f65e892b1137..2e82f4e080b1e14c668c048b1ccc3fc0672ec715 100644
--- a/AKSubmission/api.py
+++ b/AKSubmission/api.py
@@ -1,7 +1,8 @@
+from datetime import datetime
+
 from rest_framework import status
 from rest_framework.decorators import api_view
 from rest_framework.response import Response
-from django.utils.datetime_safe import datetime
 
 from AKModel.models import AK
 
diff --git a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po
index f47345a6b052651a9a8e049f95a41be97b463f07..1ccfaeb613e93c43db06c116b542e49efca85658 100644
--- a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po
+++ b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-02-27 15:13+0000\n"
+"POT-Creation-Date: 2025-03-04 14:49+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -109,21 +109,25 @@ msgstr "AK-Wunsch"
 #: AKSubmission/templates/AKSubmission/ak_detail.html:186
 #, python-format
 msgid ""
-"This AK currently takes place for another <span v-html=\"timeUntilEnd\">"
-"%(featured_slot_remaining)s</span> minute(s) in %(room)s.&nbsp;"
+"This AK currently takes place for another <span v-"
+"html=\"timeUntilEnd\">%(featured_slot_remaining)s</span> minute(s) in "
+"%(room)s.&nbsp;"
 msgstr ""
-"Dieser AK findet noch <span v-html=\"timeUntilEnd\">"
-"%(featured_slot_remaining)s</span> Minute(n) in %(room)s statt.&nbsp;\n"
+"Dieser AK findet noch <span v-"
+"html=\"timeUntilEnd\">%(featured_slot_remaining)s</span> Minute(n) in "
+"%(room)s statt.&nbsp;\n"
 "                    "
 
 #: AKSubmission/templates/AKSubmission/ak_detail.html:189
 #, python-format
 msgid ""
-"This AK starts in <span v-html=\"timeUntilStart\">"
-"%(featured_slot_remaining)s</span> minute(s) in %(room)s.&nbsp;"
+"This AK starts in <span v-"
+"html=\"timeUntilStart\">%(featured_slot_remaining)s</span> minute(s) in "
+"%(room)s.&nbsp;"
 msgstr ""
-"Dieser AK beginnt in <span v-html=\"timeUntilStart\">"
-"%(featured_slot_remaining)s</span> Minute(n) in %(room)s.&nbsp;\n"
+"Dieser AK beginnt in <span v-"
+"html=\"timeUntilStart\">%(featured_slot_remaining)s</span> Minute(n) in "
+"%(room)s.&nbsp;\n"
 "                    "
 
 #: AKSubmission/templates/AKSubmission/ak_detail.html:194
@@ -274,7 +278,7 @@ msgstr "Die Ergebnisse dieses AKs vorstellen"
 msgid "Intends to submit a resolution"
 msgstr "Beabsichtigt eine Resolution einzureichen"
 
-#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:84
+#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:82
 msgid "All AKs"
 msgstr "Alle AKs"
 
@@ -400,81 +404,80 @@ msgstr ""
 msgid "Submit"
 msgstr "Eintragen"
 
-#: AKSubmission/views.py:127
+#: AKSubmission/views.py:125
 msgid "Wishes"
 msgstr "Wünsche"
 
-#: AKSubmission/views.py:127
+#: AKSubmission/views.py:125
 msgid "AKs one would like to have"
 msgstr ""
 "AKs die sich gewünscht wurden, aber bei denen noch nicht klar ist, wer sie "
 "macht. Falls du dir das vorstellen kannst, trag dich einfach ein"
 
-#: AKSubmission/views.py:169
+#: AKSubmission/views.py:167
 msgid "Currently planned AKs"
 msgstr "Aktuell geplante AKs"
 
-#: AKSubmission/views.py:233
-msgid "AKs with Track"
-msgstr "AK mit Track"
-
-#: AKSubmission/views.py:302
+#: AKSubmission/views.py:305
 msgid "Event inactive. Cannot create or update."
 msgstr "Event inaktiv. Hinzufügen/Bearbeiten nicht möglich."
 
-#: AKSubmission/views.py:327
+#: AKSubmission/views.py:330
 msgid "AK successfully created"
 msgstr "AK erfolgreich angelegt"
 
-#: AKSubmission/views.py:400
+#: AKSubmission/views.py:404
 msgid "AK successfully updated"
 msgstr "AK erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:451
+#: AKSubmission/views.py:455
 #, python-brace-format
 msgid "Added '{owner}' as new owner of '{ak.name}'"
 msgstr "'{owner}' als neue Leitung von '{ak.name}' hinzugefügt"
 
-#: AKSubmission/views.py:555
+#: AKSubmission/views.py:558
 msgid "No user selected"
 msgstr "Keine Person ausgewählt"
 
-#: AKSubmission/views.py:571
+#: AKSubmission/views.py:574
 msgid "Person Info successfully updated"
 msgstr "Personen-Info erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:607
+#: AKSubmission/views.py:610
 msgid "AK Slot successfully added"
 msgstr "AK-Slot erfolgreich angelegt"
 
-#: AKSubmission/views.py:626
+#: AKSubmission/views.py:629
 msgid "You cannot edit a slot that has already been scheduled"
 msgstr "Bereits geplante AK-Slots können nicht mehr bearbeitet werden"
 
-#: AKSubmission/views.py:636
+#: AKSubmission/views.py:639
 msgid "AK Slot successfully updated"
 msgstr "AK-Slot erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:654
+#: AKSubmission/views.py:657
 msgid "You cannot delete a slot that has already been scheduled"
 msgstr "Bereits geplante AK-Slots können nicht mehr gelöscht werden"
 
-#: AKSubmission/views.py:664
+#: AKSubmission/views.py:667
 msgid "AK Slot successfully deleted"
 msgstr "AK-Slot erfolgreich angelegt"
 
-#: AKSubmission/views.py:676
+#: AKSubmission/views.py:679
 msgid "Messages"
 msgstr "Nachrichten"
 
-#: AKSubmission/views.py:686
+#: AKSubmission/views.py:689
 msgid "Delete all messages"
 msgstr "Alle Nachrichten löschen"
 
-#: AKSubmission/views.py:713
+#: AKSubmission/views.py:716
 msgid "Message to organizers successfully saved"
 msgstr "Nachricht an die Organisator*innen erfolgreich gespeichert"
 
+#~ msgid "AKs with Track"
+#~ msgstr "AK mit Track"
+
 #~ msgid ""
 #~ "Due to technical reasons, the link you entered was truncated to a length "
 #~ "of 200 characters"
diff --git a/AKSubmission/tests.py b/AKSubmission/tests.py
index 8180ea3c10a4b5d28d741467bbc6df4906f25003..fd31454391bbc15ed42ba5e77a1e6da5b04f1461 100644
--- a/AKSubmission/tests.py
+++ b/AKSubmission/tests.py
@@ -1,8 +1,7 @@
-from datetime import timedelta
+from datetime import datetime, timedelta
 
 from django.test import TestCase
 from django.urls import reverse_lazy
-from django.utils.datetime_safe import datetime
 
 from AKModel.models import AK, AKSlot, Event
 from AKModel.tests.test_views import BasicViewTests
@@ -47,8 +46,8 @@ class ModelViewTests(BasicViewTests, TestCase):
          'expected_message': "AK successfully updated"},
         {'view': 'akslot_edit', 'target_view': 'ak_detail', 'kwargs': {'event_slug': 'kif42', 'pk': 5},
          'target_kwargs': {'event_slug': 'kif42', 'pk': 1}, 'expected_message': "AK Slot successfully updated"},
-        {'view': 'akowner_edit', 'target_view': 'submission_overview', 'kwargs': {'event_slug': 'kif42',  'slug': 'a'},
-          'target_kwargs': {'event_slug': 'kif42'}, 'expected_message': "Person Info successfully updated"},
+        {'view': 'akowner_edit', 'target_view': 'submission_overview', 'kwargs': {'event_slug': 'kif42', 'slug': 'a'},
+         'target_kwargs': {'event_slug': 'kif42'}, 'expected_message': "Person Info successfully updated"},
     ]
 
     def test_akslot_edit_delete_prevention(self):
@@ -147,7 +146,8 @@ class ModelViewTests(BasicViewTests, TestCase):
         add_redirect_url = reverse_lazy(f"{self.APP_NAME}:submit_ak", kwargs={'event_slug': 'kif42', 'owner_slug': 'a'})
         response = self.client.post(select_url, {'owner_id': 1})
         self.assertRedirects(response, add_redirect_url, status_code=302, target_status_code=200,
-                    msg_prefix=f"Dispatch redirect to ak submission page failed (should go to {add_redirect_url})")
+                             msg_prefix=f"Dispatch redirect to ak submission page failed "
+                                        f"(should go to {add_redirect_url})")
 
     def test_orga_message_submission(self):
         """
@@ -201,7 +201,8 @@ class ModelViewTests(BasicViewTests, TestCase):
         # Test indication outside of indication window -> HTTP 403, counter not increased
         response = self.client.post(interest_api_url)
         self.assertEqual(response.status_code, 403,
-                    "API end point still reachable even though interest indication window ended ({interest_api_url})")
+                         "API end point still reachable even though interest indication window ended "
+                         "({interest_api_url})")
         self.assertEqual(AK.objects.get(pk=1).interest_counter, ak_interest_counter + 1,
                          "Counter was increased even though interest indication window ended")
 
@@ -243,13 +244,14 @@ class ModelViewTests(BasicViewTests, TestCase):
         Test visibility of requirements field in submission form
         """
         event = Event.get_by_slug('kif42')
-        form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event":event})
+        form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event": event})
         self.assertIn('requirements', form.fields,
                       msg="Requirements field not present in form even though event has requirements")
 
         event2 = Event.objects.create(name='Event without requirements',
                                       slug='no_req',
-                                      start=datetime.now(), end=datetime.now(),
+                                      start=datetime.now().astimezone(event.timezone),
+                                      end=datetime.now().astimezone(event.timezone),
                                       active=True)
         form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2})
         self.assertNotIn('requirements', form2.fields,
@@ -260,13 +262,14 @@ class ModelViewTests(BasicViewTests, TestCase):
         Test visibility of types field in submission form
         """
         event = Event.get_by_slug('kif42')
-        form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event":event})
+        form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event": event})
         self.assertIn('types', form.fields,
                       msg="Requirements field not present in form even though event has requirements")
 
         event2 = Event.objects.create(name='Event without types',
                                       slug='no_types',
-                                      start=datetime.now(), end=datetime.now(),
+                                      start=datetime.now().astimezone(event.timezone),
+                                      end=datetime.now().astimezone(event.timezone),
                                       active=True)
         form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2})
         self.assertNotIn('types', form2.fields,
diff --git a/AKSubmission/views.py b/AKSubmission/views.py
index 5263b875ea21399a5f98d37914403c2f674ec391..3bbffa1f55da2c52e635f6349642de921d6b3cad 100644
--- a/AKSubmission/views.py
+++ b/AKSubmission/views.py
@@ -1,6 +1,6 @@
-from datetime import timedelta
-from math import floor
 from abc import ABC, abstractmethod
+from datetime import datetime, timedelta
+from math import floor
 
 from django.apps import apps
 from django.conf import settings
@@ -8,19 +8,17 @@ from django.contrib import messages
 from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse_lazy
-from django.utils.datetime_safe import datetime
 from django.utils.translation import gettext_lazy as _
 from django.views import View
-from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
+from django.views.generic import CreateView, DeleteView, DetailView, ListView, TemplateView, UpdateView
 
 from AKModel.availability.models import Availability
 from AKModel.metaviews import status_manager
-from AKModel.metaviews.status import TemplateStatusWidget
-from AKModel.models import AK, AKCategory, AKOwner, AKSlot, AKTrack, AKOrgaMessage
 from AKModel.metaviews.admin import EventSlugMixin, FilterByEventSlugMixin
+from AKModel.metaviews.status import TemplateStatusWidget
+from AKModel.models import AK, AKCategory, AKOrgaMessage, AKOwner, AKSlot, AKTrack
 from AKSubmission.api import ak_interest_indication_active
-from AKSubmission.forms import AKWishForm, AKOwnerForm, AKSubmissionForm, AKDurationForm, AKOrgaMessageForm, \
-    AKForm
+from AKSubmission.forms import AKDurationForm, AKForm, AKOrgaMessageForm, AKOwnerForm, AKSubmissionForm, AKWishForm
 
 
 class SubmissionErrorNotConfiguredView(EventSlugMixin, TemplateView):
@@ -47,7 +45,7 @@ class AKOverviewView(FilterByEventSlugMixin, ListView):
     template_name = "AKSubmission/ak_overview.html"
     wishes_as_category = False
 
-    def filter_aks(self, context, category): # pylint: disable=unused-argument
+    def filter_aks(self, context, category):  # pylint: disable=unused-argument
         """
         Filter which AKs to display based on the given context and category
 
@@ -73,7 +71,7 @@ class AKOverviewView(FilterByEventSlugMixin, ListView):
         """
         return context["categories_with_aks"][0][0].name
 
-    def get_table_title(self, context): # pylint: disable=unused-argument
+    def get_table_title(self, context):  # pylint: disable=unused-argument
         """
         Specify the title above the AK list/table in this view
 
@@ -91,7 +89,7 @@ class AKOverviewView(FilterByEventSlugMixin, ListView):
         redirect to error page if necessary (see :class:`SubmissionErrorNotConfiguredView`)
         """
         self._load_event()
-        self.object_list = self.get_queryset() # pylint: disable=attribute-defined-outside-init
+        self.object_list = self.get_queryset()  # pylint: disable=attribute-defined-outside-init
 
         # No categories yet? Redirect to configuration error page
         if self.object_list.count() == 0:
@@ -124,7 +122,7 @@ class AKOverviewView(FilterByEventSlugMixin, ListView):
 
         if self.wishes_as_category:
             categories_with_aks.append(
-                (AKCategory(name=_("Wishes"), pk=0, description=_("AKs one would like to have")), ak_wishes))
+                    (AKCategory(name=_("Wishes"), pk=0, description=_("AKs one would like to have")), ak_wishes))
 
         context["categories_with_aks"] = categories_with_aks
         context["active_category"] = self.get_active_category_name(context)
@@ -183,10 +181,13 @@ class AKListByCategoryView(AKOverviewView):
 
     This view inherits from :class:`AKOverviewView`, but produces only one list instead of a tabbed one.
     """
+
     def dispatch(self, request, *args, **kwargs):
         # Override dispatching
         # Needed to handle the checking whether the category exists
-        self.category = get_object_or_404(AKCategory, pk=kwargs['category_pk']) # pylint: disable=attribute-defined-outside-init,line-too-long
+        # noinspection PyAttributeOutsideInit
+        # pylint: disable=attribute-defined-outside-init
+        self.category = get_object_or_404(AKCategory, pk=kwargs['category_pk'])
         return super().dispatch(request, *args, **kwargs)
 
     def get_active_category_name(self, context):
@@ -209,11 +210,12 @@ class AKListByTrackView(AKOverviewView):
     This view inherits from :class:`AKOverviewView` and there will be one list per category
     -- but only AKs of a certain given track will be included in them.
     """
+
     def dispatch(self, request, *args, **kwargs):
         # Override dispatching
         # Needed to handle the checking whether the track exists
 
-        self.track = get_object_or_404(AKTrack, pk=kwargs['track_pk']) # pylint: disable=attribute-defined-outside-init
+        self.track = get_object_or_404(AKTrack, pk=kwargs['track_pk'])  # pylint: disable=attribute-defined-outside-init
         return super().dispatch(request, *args, **kwargs)
 
     def filter_aks(self, context, category):
@@ -292,6 +294,7 @@ class EventInactiveRedirectMixin:
     Will add a message explaining why the action was not performed to the user
     and then redirect to start page of the submission component
     """
+
     def get_error_message(self):
         """
         Error message to display after redirect (can be adjusted by this method)
@@ -351,6 +354,7 @@ class AKSubmissionView(AKAndAKWishSubmissionView):
 
     Extends :class:`AKAndAKWishSubmissionView`
     """
+
     def get_initial(self):
         # Load initial values for the form
         # Used to directly add the first owner and the event this AK will belong to
@@ -500,7 +504,6 @@ class AKOwnerDispatchView(ABC, EventSlugMixin, View):
         :rtype: HttpResponseRedirect
         """
 
-
     def post(self, request, *args, **kwargs):
         # This view is solely meant to handle POST requests
         # Perform dispatching based on the submitted owner_id
diff --git a/INSTALL.md b/INSTALL.md
index 5344a998cffe2603aaaffb0583e91fb43e533c38..4c98ce7b4bdbfdbc21ac3429199ff4a5786e1294 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -10,7 +10,7 @@ setup.
 
 ### System Requirements
 
-* Python 3.10+ incl. development tools
+* Python 3.11+ incl. development tools
 * Virtualenv
 * pdflatex & beamer
   class (`texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-fonts-extra texlive-luatex`)
@@ -37,7 +37,7 @@ Python requirements are listed in ``requirements.txt``. They can be installed wi
 
 ### Manual Setup
 
-1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.10``
+1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.11``
 1. activate virtualenv ``source venv/bin/activate``
 1. install python requirements ``pip install -r requirements.txt``
 1. setup necessary database tables etc. ``python manage.py migrate``
@@ -68,7 +68,7 @@ is not stored in any repository or similar, and disable DEBUG mode (``settings.p
 1. create a folder, e.g. ``mkdir /srv/AKPlanning/``
 1. change to the new directory ``cd /srv/AKPlanning/``
 1. clone this repository ``git clone URL .``
-1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.10``
+1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.11``
 1. activate virtualenv ``source venv/bin/activate``
 1. update tools ``pip install --upgrade setuptools pip wheel``
 1. install python requirements ``pip install -r requirements.txt``
diff --git a/Utils/check.sh b/Utils/check.sh
index c2e09f5b8852b9a2e70b9c9f6f9e1296c1404f02..1cdbdf7d85687b820c0a16f98217d367ac8b3ccf 100755
--- a/Utils/check.sh
+++ b/Utils/check.sh
@@ -8,14 +8,20 @@ if [ -z ${VIRTUAL_ENV+x} ]; then
 fi
 
 # enable really all warnings, some of them are silenced by default
-if [[ "$@" == *"--all"* ]]; then
-    export PYTHONWARNINGS=all
-fi
+for arg in "$@"; do
+    if [[ "$arg" == "--all" ]]; then
+        export PYTHONWARNINGS=all
+    fi
+done
 
 # in case of checking production setup
-if [[ "$@" == *"--prod"* ]]; then
-    export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production
-    ./manage.py check --deploy
-fi
+for arg in "$@"; do
+    if [[ "$arg" == "--prod" ]]; then
+      export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production
+      ./manage.py check --deploy
+    fi
+done
 
+# check the setup
 ./manage.py check
+./manage.py makemigrations --dry-run --check
diff --git a/Utils/setup.sh b/Utils/setup.sh
index 6a93207d197e75da2875b31ea8e0e631e114e837..1123bbd8ae707b4b15d2aef6ec33a0ec68a1e2e9 100755
--- a/Utils/setup.sh
+++ b/Utils/setup.sh
@@ -10,7 +10,7 @@ rm -rf venv/
 
 # Setup Python Environment
 # Requires: Virtualenv, appropriate Python installation
-virtualenv venv -p python3.10
+virtualenv venv -p python3.11
 source venv/bin/activate
 pip install --upgrade setuptools pip wheel
 pip install -r requirements.txt
diff --git a/Utils/test.sh b/Utils/test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ab6dbb2b9f23f3427b773715c5fa4ba1d74c179e
--- /dev/null
+++ b/Utils/test.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Test the AKPlanning setup
+# execute as Utils/test.sh
+
+# activate virtualenv when necessary
+if [ -z ${VIRTUAL_ENV+x} ]; then
+    source venv/bin/activate
+fi
+
+# enable really all warnings, some of them are silenced by default
+for arg in "$@"; do
+    if [[ "$arg" == "--all" ]]; then
+        export PYTHONWARNINGS=all
+    fi
+done
+
+# in case of checking production setup
+for arg in "$@"; do
+    if [[ "$arg" == "--prod" ]]; then
+      export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production
+      ./manage.py test --deploy
+    fi
+done
+
+# run tests
+./manage.py test
diff --git a/Utils/update.sh b/Utils/update.sh
index a711b73b912fcd07e8543b6b49d4eb8950ff0d79..d81aae52947404ac629050ba2c2d69c19e4b37e5 100755
--- a/Utils/update.sh
+++ b/Utils/update.sh
@@ -19,7 +19,7 @@ fi
 mkdir -p backups/
 python manage.py dumpdata --indent=2 > "backups/$(date +"%Y%m%d%H%M")_datadump.json" --traceback
 
-git pull
+# git pull
 pip install --upgrade setuptools pip wheel
 pip install --upgrade -r requirements.txt
 
diff --git a/requirements.txt b/requirements.txt
index 451feef4db2ee295a38687bc0f96ff1dee637418..be46f86ad6caa490c27ac703e3de38154a542b6b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,26 +1,31 @@
-Django==4.2.13
-django-bootstrap5==24.2
-fontawesomefree==6.5.1 # Makes static files (css, fonts) available locally
-django-fontawesome-6==1.0.0.0 # Provides an icon field for models and forms as well as handy shortcuts to render icons
-django-split-settings==1.3.1
-django-timezone-field==6.1.0
-djangorestframework==3.15.1
-django-simple-history==3.5.0
-django-registration-redux==2.13
-django-debug-toolbar==4.3.0
+Django==5.1.6
+django-betterforms==2.0.0
 django-bootstrap-datepicker-plus==5.0.5
-django-tex==1.1.10
-django-csp==3.8
-django-compressor==4.4
+django-bootstrap5==25.1
+django-compressor==4.5.1
+django-debug-toolbar==5.0.1
+django-fontawesome-6==1.0.0.0  # Provides an icon field for models and forms as well as handy shortcuts to render icons
 django-libsass==0.9
-django-betterforms==2.0.0
-mysqlclient==2.2.0  # for production deployment
-tzdata==2024.1
+django-registration-redux==2.13
+django-simple-history==3.8.0
+django-split-settings==1.3.2
+django-tex==1.1.10
+django-timezone-field==7.1
+django_csp==3.8
+djangorestframework==3.15.2
+
+fontawesomefree==6.6.0  # Makes static files (css, fonts) available locally
+# mysqlclient==2.2.7  # for production deployment
+tzdata==2025.1
+
+# Tests
+beautifulsoup4==4.13.3
+lxml==5.3.1
 
 # Documentation
-sphinxcontrib-django==2.5
+Sphinx==8.2.3
+sphinx-rtd-theme==3.0.2
 sphinxcontrib-apidoc==0.5.0
+sphinxcontrib-django==2.5.0
 recommonmark==0.7.1
 django-docs==0.3.3
-sphinx-rtd-theme==2.0.0
-sphinx==7.3.7