diff --git a/aleksis/core/checks.py b/aleksis/core/checks.py
index 9518b5e26bfe2f8d2cc8eff7494eeb6f4495035d..db3199b6081d77e9bd8e2c559db07f7924484599 100644
--- a/aleksis/core/checks.py
+++ b/aleksis/core/checks.py
@@ -11,7 +11,7 @@ from .util.apps import AppConfig
 def check_app_configs_base_class(
     app_configs: Optional[django.apps.registry.Apps] = None, **kwargs
 ) -> list:
-    """Checks whether all apps derive from AlekSIS's base app config."""
+    """Check whether all apps derive from AlekSIS's base app config."""
     results = []
 
     if app_configs is None:
@@ -39,7 +39,7 @@ def check_app_configs_base_class(
 def check_app_models_base_class(
     app_configs: Optional[django.apps.registry.Apps] = None, **kwargs
 ) -> list:
-    """Checks whether all app models derive from AlekSIS's base ExtensibleModel."""
+    """Check whether all app models derive from AlekSIS's base ExtensibleModel."""
     results = []
 
     if app_configs is None:
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index 94283722c9d58168c245668c1a2a77d9e79b697d..d0b44263b1ccdcb73fcba55ee7e7aff36d44d5bd 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -142,22 +142,22 @@ class ExtensibleModel(models.Model):
 
     @classmethod
     def property(cls, func: Callable[[], Any], name: Optional[str] = None) -> None:
-        """Adds the passed callable as a property."""
+        """Add the passed callable as a property."""
         cls._safe_add(property(func), func.__name__)
 
     @classmethod
     def method(cls, func: Callable[[], Any], name: Optional[str] = None) -> None:
-        """Adds the passed callable as a method."""
+        """Add the passed callable as a method."""
         cls._safe_add(func, func.__name__)
 
     @classmethod
     def class_method(cls, func: Callable[[], Any], name: Optional[str] = None) -> None:
-        """Adds the passed callable as a classmethod."""
+        """Add the passed callable as a classmethod."""
         cls._safe_add(classmethod(func), func.__name__)
 
     @classmethod
     def field(cls, **kwargs) -> None:
-        """Adds the passed jsonstore field. Must be one of the fields in django-jsonstore.
+        """Add the passed jsonstore field. Must be one of the fields in django-jsonstore.
 
         Accepts exactly one keyword argument, with the name being the desired
         model field name and the value the field instance.
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index d924a7fdaabdcbb9e4c2aa728a390ce0e71cc54d..b22c4e729235a961902a0a95890b9e92f6ac35e6 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -38,11 +38,13 @@ FIELD_CHOICES = (
     ("TextField", _("Text (multi-line)")),
     ("TimeField", _("Time")),
     ("URLField", _("URL / Link")),
+
 )
 
 
 class Person(ExtensibleModel):
-    """
+    """Person model.
+
     A model describing any person related to a school, including, but not
     limited to, students, teachers and guardians (parents).
     """
@@ -80,7 +82,7 @@ class Person(ExtensibleModel):
     )
 
     short_name = models.CharField(
-        verbose_name=_("Short name"), max_length=255, blank=True, null=True, unique=True
+        verbose_name=_("Short name"), max_length=255, blank=True, unique=True
     )
 
     street = models.CharField(verbose_name=_("Street"), max_length=255, blank=True)
@@ -111,21 +113,21 @@ class Person(ExtensibleModel):
         "Group", models.SET_NULL, null=True, blank=True, verbose_name=_("Primary group")
     )
 
-    description = models.TextField(verbose_name=_("Description"), blank=True, null=True)
+    description = models.TextField(verbose_name=_("Description"), blank=True)
 
     def get_absolute_url(self) -> str:
         return reverse("person_by_id", args=[self.id])
 
     @property
     def primary_group_short_name(self) -> Optional[str]:
-        """Returns the short_name field of the primary group related object."""
+        """Return the short_name field of the primary group related object."""
         if self.primary_group:
             return self.primary_group.short_name
 
     @primary_group_short_name.setter
     def primary_group_short_name(self, value: str) -> None:
         """
-        Sets the primary group related object by a short name.
+        Set the primary group related object by a short name.
 
         It uses the first existing group
         with this short name it can find, creating one
@@ -237,7 +239,8 @@ class AdditionalField(ExtensibleModel):
 
 
 class Group(ExtensibleModel):
-    """
+    """Group model.
+
     Any kind of group of persons in a school, including, but not limited
     classes, clubs, and the like.
     """
@@ -252,7 +255,7 @@ class Group(ExtensibleModel):
 
     name = models.CharField(verbose_name=_("Long name"), max_length=255, unique=True)
     short_name = models.CharField(
-        verbose_name=_("Short name"), max_length=255, unique=True, blank=True, null=True
+        verbose_name=_("Short name"), max_length=255, unique=True, blank=True
     )
 
     members = models.ManyToManyField(
@@ -387,7 +390,8 @@ class AnnouncementQuerySet(models.QuerySet):
     """Queryset for announcements providing time-based utility functions."""
 
     def relevant_for(self, obj: Union[models.Model, models.QuerySet]) -> models.QuerySet:
-        """
+        """Get all relevant announcements.
+
         Get a QuerySet with all announcements relevant for a certain Model (e.g. a Group)
         or a set of models in a QuerySet.
         """
@@ -437,7 +441,8 @@ class AnnouncementQuerySet(models.QuerySet):
 
 
 class Announcement(ExtensibleModel):
-    """
+    """Announcement model.
+
     Persistent announcement to display to groups or persons in various places during a
     specific time range.
     """
@@ -464,7 +469,7 @@ class Announcement(ExtensibleModel):
         return persons
 
     def get_recipients_for_model(self, obj: Union[models.Model]) -> Sequence[models.Model]:
-        """
+        """Get all recipients.
         Get all recipients for this announcement
         with a special content type (provided through model)
         """
@@ -480,7 +485,8 @@ class Announcement(ExtensibleModel):
 
 
 class AnnouncementRecipient(ExtensibleModel):
-    """
+    """Announcement recipient model.
+
     Generalisation of a recipient for an announcement, used to wrap arbitrary
     objects that can receive announcements.
 
@@ -564,14 +570,15 @@ class DashboardWidget(PolymorphicModel, PureDjangoModel):
     media = Media()
 
     title = models.CharField(max_length=150, verbose_name=_("Widget Title"))
-    active = models.BooleanField(blank=True, verbose_name=_("Activate Widget"))
+    active = models.BooleanField(verbose_name=_("Activate Widget"))
 
     def get_context(self):
         """Get the context dictionary to pass to the widget template."""
         raise NotImplementedError("A widget subclass needs to implement the get_context method.")
 
     def get_template(self):
-        """
+        """Get template.
+
         Get the template to render the widget with. Defaults to the template attribute,
         but can be overridden to allow more complex template generation scenarios.
         """
@@ -613,7 +620,7 @@ class CustomMenuItem(ExtensibleModel):
     name = models.CharField(max_length=150, verbose_name=_("Name"))
     url = models.URLField(verbose_name=_("Link"))
     icon = models.CharField(
-        max_length=50, blank=True, null=True, choices=ICONS, verbose_name=_("Icon")
+        max_length=50, blank=True, choices=ICONS, verbose_name=_("Icon")
     )
 
     def __str__(self):
@@ -625,7 +632,8 @@ class CustomMenuItem(ExtensibleModel):
 
 
 class GroupType(ExtensibleModel):
-    """
+    """Group type model.
+
     Descriptive type of a group; used to tag groups and for apps to distinguish
     how to display or handle a certain group.
     """
diff --git a/aleksis/core/util/apps.py b/aleksis/core/util/apps.py
index 0f101a11d19a6097fd7c04dc54de266cf340f79f..11bc70d1bbffe2b986c3543f708aa8b1f4dba10b 100644
--- a/aleksis/core/util/apps.py
+++ b/aleksis/core/util/apps.py
@@ -2,6 +2,7 @@ from importlib import import_module
 from typing import Any, List, Optional, Sequence, Tuple
 
 import django.apps
+from django.contrib.auth import get_user_model
 from django.contrib.auth.signals import user_logged_in, user_logged_out
 from django.db.models.signals import post_migrate, pre_migrate
 from django.http import HttpRequest
@@ -13,6 +14,9 @@ from spdx_license_list import LICENSES
 from .core_helpers import copyright_years
 
 
+User = get_user_model()
+
+
 class AppConfig(django.apps.AppConfig):
     """An extended version of DJango's AppConfig container."""
 
@@ -149,7 +153,7 @@ class AppConfig(django.apps.AppConfig):
         new_value: Optional[Any] = None,
         **kwargs,
     ) -> None:
-        """Called on every app instance if a dynamic preference changes, and once on startup.
+        """Call on every app instance if a dynamic preference changes, and once on startup.
 
         By default, it does nothing.
         """
@@ -165,7 +169,7 @@ class AppConfig(django.apps.AppConfig):
         apps: django.apps.registry.Apps,
         **kwargs,
     ) -> None:
-        """Called on every app instance before its models are migrated.
+        """Call on every app instance before its models are migrated.
 
         By default, it does nothing.
         """
@@ -181,7 +185,7 @@ class AppConfig(django.apps.AppConfig):
         apps: django.apps.registry.Apps,
         **kwargs,
     ) -> None:
-        """Called on every app instance after its models have been migrated.
+        """Call on every app instance after its models have been migrated.
 
         By default, asks all models to do maintenance on their default data.
         """
@@ -190,7 +194,7 @@ class AppConfig(django.apps.AppConfig):
     def user_logged_in(
         self, sender: type, request: Optional[HttpRequest], user: "User", **kwargs
     ) -> None:
-        """Called after a user logged in.
+        """Call after a user logged in.
 
         By default, it does nothing.
         """
@@ -199,7 +203,7 @@ class AppConfig(django.apps.AppConfig):
     def user_logged_out(
         self, sender: type, request: Optional[HttpRequest], user: "User", **kwargs
     ) -> None:
-        """Called after a user logged out.
+        """Call after a user logged out.
 
         By default, it does nothing.
         """
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index 79bf5059443aa64aa8c45deb007c6b5619e30285..67c9daae584fbdbe84294b8439d7cfb20481aa01 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -16,7 +16,7 @@ from django.utils.functional import lazy
 
 
 def copyright_years(years: Sequence[int], seperator: str = ", ", joiner: str = "–") -> str:
-    """Takes a sequence of integegers and produces a string with ranges.
+    """Take a sequence of integegers and produces a string with ranges.
 
     >>> copyright_years([1999, 2000, 2001, 2005, 2007, 2008, 2009])
     '1999–2001, 2005, 2007–2009'
@@ -34,7 +34,7 @@ def copyright_years(years: Sequence[int], seperator: str = ", ", joiner: str = "
 
 
 def dt_show_toolbar(request: HttpRequest) -> bool:
-    """Helper to determin if Django debug toolbar should be displayed.
+    """Add a helper to determin if Django debug toolbar should be displayed.
 
     Extends the default behaviour by enabling DJDT for superusers independent
     of source IP.
@@ -66,7 +66,8 @@ def get_app_packages() -> Sequence[str]:
 def merge_app_settings(
     setting: str, original: Union[dict, list], deduplicate: bool = False
 ) -> Union[dict, list]:
-    """
+    """Merge app settings.
+
     Get a named settings constant from all apps and merge it into the original.
     To use this, add a settings.py file to the app, in the same format as Django's
     main settings.py.
@@ -170,7 +171,7 @@ def has_person(obj: Union[HttpRequest, Model]) -> bool:
 
 
 def celery_optional(orig: Callable) -> Callable:
-    """Decorator that makes Celery optional for a function.
+    """Add a decorator that makes Celery optional for a function.
 
     If Celery is configured and available, it wraps the function in a Task
     and calls its delay method when invoked; if not, it leaves it untouched
@@ -191,7 +192,7 @@ def celery_optional(orig: Callable) -> Callable:
 
 
 def path_and_rename(instance, filename: str, upload_to: str = "files") -> str:
-    """Updates path of an uploaded file and renames it to a random UUID in Django FileField."""
+    """Update path of an uploaded file and renames it to a random UUID in Django FileField."""
     _, ext = os.path.splitext(filename)
 
     # set filename as random string
@@ -205,7 +206,7 @@ def path_and_rename(instance, filename: str, upload_to: str = "files") -> str:
 
 
 def custom_information_processor(request: HttpRequest) -> dict:
-    """Provides custom information in all templates."""
+    """Provide custom information in all templates."""
     from ..models import CustomMenu
 
     return {
diff --git a/aleksis/core/util/messages.py b/aleksis/core/util/messages.py
index bd125d1cb46b54d890dd80850627d06406f153f2..5efc04c12befb65825164f8f954eedbd4dc4500c 100644
--- a/aleksis/core/util/messages.py
+++ b/aleksis/core/util/messages.py
@@ -8,7 +8,9 @@ from django.http import HttpRequest
 def add_message(
     request: Optional[HttpRequest], level: int, message: str, **kwargs
 ) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add a message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to DEBUG level.
@@ -20,7 +22,9 @@ def add_message(
 
 
 def debug(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add a debug message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to DEBUG level.
@@ -29,7 +33,9 @@ def debug(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[An
 
 
 def info(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add a info message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to INFO level.
@@ -38,7 +44,9 @@ def info(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any
 
 
 def success(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add a success message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to SUCCESS level.
@@ -47,7 +55,9 @@ def success(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[
 
 
 def warning(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add a warning message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to WARNING level.
@@ -56,7 +66,9 @@ def warning(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[
 
 
 def error(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
-    """ Add a message to either Django's message framework, if called from a web request,
+    """Add an error message.
+
+    Add a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to ERROR level.
diff --git a/aleksis/core/util/notifications.py b/aleksis/core/util/notifications.py
index 2c7172a1d28a0c69c705fd9390e090ffdac61e3c..1a770a7818e88212494ab9442421a546bede93bf 100644
--- a/aleksis/core/util/notifications.py
+++ b/aleksis/core/util/notifications.py
@@ -11,6 +11,7 @@ from django.utils.translation import gettext_lazy as _
 from templated_email import send_templated_mail
 
 from .core_helpers import lazy_preference
+from ..models import Notification
 
 try:
     from twilio.rest import Client as TwilioClient
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
index da099c3a948d5ab05c36803922b61bd8b6a743d5..0e452ddb0cb560ba4edbe174c560ade56c6261ed 100644
--- a/aleksis/core/util/predicates.py
+++ b/aleksis/core/util/predicates.py
@@ -13,24 +13,24 @@ from .core_helpers import has_person as has_person_helper
 
 
 def permission_validator(request: HttpRequest, perm: str) -> bool:
-    """Checks whether the request user has a permission."""
+    """Check whether the request user has a permission."""
     if request.user:
         return request.user.has_perm(perm)
     return False
 
 
 def check_global_permission(user: User, perm: str) -> bool:
-    """Checks whether a user has a global permission."""
+    """Check whether a user has a global permission."""
     return ModelBackend().has_perm(user, perm)
 
 
 def check_object_permission(user: User, perm: str, obj: Model) -> bool:
-    """Checks whether a user has a permission on a object."""
+    """Check whether a user has a permission on a object."""
     return ObjectPermissionBackend().has_perm(user, perm, obj)
 
 
 def has_global_perm(perm: str):
-    """Builds predicate which checks whether a user has a global permission."""
+    """Build predicate which checks whether a user has a global permission."""
     name = f"has_global_perm:{perm}"
 
     @predicate(name)
@@ -41,7 +41,7 @@ def has_global_perm(perm: str):
 
 
 def has_object_perm(perm: str):
-    """Builds predicate which checks whether a user has a permission on a object."""
+    """Build predicate which checks whether a user has a permission on a object."""
     name = f"has_global_perm:{perm}"
 
     @predicate(name)
@@ -54,8 +54,10 @@ def has_object_perm(perm: str):
 
 
 def has_any_object(perm: str, klass):
-    """
-    Build predicate which checks whether a user has access to objects with the provided permission.
+    """Check if has any object.
+
+    Build predicate which checks whether a user has access
+    to objects with the provided permission.
     """
     name = f"has_any_object:{perm}"
 
@@ -98,7 +100,8 @@ def is_group_owner(user: User, group: Group) -> bool:
 
 @predicate
 def is_notification_recipient(user: User, obj: Model) -> bool:
-    """
+    """Check if is a notification recipient.
+
     Predicate which checks whether the recipient of the
     notification a user wants to mark read is this user.
     """
diff --git a/aleksis/core/util/search.py b/aleksis/core/util/search.py
index 437887ae6412c0e3f8b493908346be8315b69481..22abef17c59d667f0954eb22c15dbab71b64aae2 100644
--- a/aleksis/core/util/search.py
+++ b/aleksis/core/util/search.py
@@ -12,7 +12,7 @@ else:
 
 
 class SearchIndex(BaseSearchIndex):
-    """ Base class for search indexes on AlekSIS models.
+    """Base class for search indexes on AlekSIS models.
 
     It provides a default document field caleld text and exects
     the related model in the model attribute.