diff --git a/aleksis/core/checks.py b/aleksis/core/checks.py
index c1a3dfb242946c67bf484fb8c9b485ec9c0b1b06..ebd6f8844c0e234af8685d70592485e8bd95efa4 100644
--- a/aleksis/core/checks.py
+++ b/aleksis/core/checks.py
@@ -11,8 +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 """
-
+    """Checks whether all apps derive from AlekSIS's base app config"""
     results = []
 
     if app_configs is None:
@@ -40,8 +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 """
-
+    """Checks whether all app models derive from AlekSIS's base ExtensibleModel"""
     results = []
 
     if app_configs is None:
diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py
index 09f57a249ef556855e8070f68c37199a80b66386..a359415a8ee58350bca0537a101b31ad1050e0ed 100644
--- a/aleksis/core/forms.py
+++ b/aleksis/core/forms.py
@@ -19,7 +19,7 @@ from .registries import (
 
 
 class PersonAccountForm(forms.ModelForm):
-    """ Form to assign user accounts to persons in the frontend :"""
+    """Form to assign user accounts to persons in the frontend :"""
 
     class Meta:
         model = Person
@@ -67,7 +67,7 @@ PersonsAccountsFormSet = forms.modelformset_factory(
 
 
 class EditPersonForm(ExtensibleForm):
-    """ Form to edit an existing person object in the frontend """
+    """Form to edit an existing person object in the frontend"""
 
     layout = Layout(
         Fieldset(
@@ -122,7 +122,7 @@ class EditPersonForm(ExtensibleForm):
 
 
 class EditGroupForm(ExtensibleForm):
-    """ Form to edit an existing group in the frontend """
+    """Form to edit an existing group in the frontend"""
 
     layout = Layout(
         Fieldset(_("Common data"), "name", "short_name"),
@@ -154,7 +154,7 @@ class EditGroupForm(ExtensibleForm):
 
 
 class AnnouncementForm(ExtensibleForm):
-    """ Form to create or edit an announcement in the frontend """
+    """Form to create or edit an announcement in the frontend"""
 
     valid_from = forms.DateTimeField(required=False)
     valid_until = forms.DateTimeField(required=False)
@@ -259,24 +259,24 @@ class AnnouncementForm(ExtensibleForm):
 
 
 class ChildGroupsForm(forms.Form):
-    """ Inline form for group editing to select child groups """
+    """Inline form for group editing to select child groups"""
 
     child_groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all())
 
 
 class SitePreferenceForm(PreferenceForm):
-    """ Form to edit site preferences """
+    """Form to edit site preferences"""
 
     registry = site_preferences_registry
 
 
 class PersonPreferenceForm(PreferenceForm):
-    """ Form to edit preferences valid for one person"""
+    """Form to edit preferences valid for one person"""
 
     registry = person_preferences_registry
 
 
 class GroupPreferenceForm(PreferenceForm):
-    """ Form to edit preferences valid for members of a group"""
+    """Form to edit preferences valid for members of a group"""
 
     registry = group_preferences_registry
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index 2041ca713c95f1df0504fb6832f57546a9066e79..c391b5d084e3dbd61d8fab278312690b20c300c7 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -18,7 +18,7 @@ from rules.contrib.admin import ObjectPermissionsModelAdmin
 
 @reversion.register()
 class ExtensibleModel():
-    """ Base model for all objects in AlekSIS apps
+    """Base model for all objects in AlekSIS apps
 
     This base model ensures all objects in AlekSIS apps fulfill the
     following properties:
@@ -65,18 +65,18 @@ class ExtensibleModel():
     # Defines a material design icon associated with this type of model
     icon_ = "radio_button_unchecked"
 
-    site = models.ForeignKey(Site, on_delete=models.CASCADE, default=Site.objects.get_current, editable=False)
+    site = models.ForeignKey(Site, on_delete=models.CASCADE,
+                             default=Site.objects.get_current, editable=False)
     objects = CurrentSiteManager()
     objects_all_sites = models.Manager()
 
     def get_absolute_url(self) -> str:
-        """ Get the URL o a view representing this model instance """
+        """Get the URL o a view representing this model instance"""
         pass
 
     @property
     def crud_events(self) -> QuerySet:
-        """ Get all CRUD events connected to this object from easyaudit """
-
+        """Get all CRUD events connected to this object from easyaudit"""
         content_type = ContentType.objects.get_for_model(self)
 
         return CRUDEvent.objects.filter(
@@ -85,25 +85,23 @@ class ExtensibleModel():
 
     @property
     def crud_event_create(self) -> Optional[CRUDEvent]:
-        """ Return create event of this object """
+        """Return create event of this object"""
         return self.crud_events.filter(event_type=CRUDEvent.CREATE).latest("datetime")
 
     @property
     def crud_event_update(self) -> Optional[CRUDEvent]:
-        """ Return last event of this object """
+        """Return last event of this object"""
         return self.crud_events.latest("datetime")
 
     @property
     def created_at(self) -> Optional[datetime]:
-        """ Determine creation timestamp from CRUD log """
-
+        """Determine creation timestamp from CRUD log"""
         if self.crud_event_create:
             return self.crud_event_create.datetime
 
     @property
     def updated_at(self) -> Optional[datetime]:
-        """ Determine last timestamp from CRUD log """
-
+        """Determine last timestamp from CRUD log"""
         if self.crud_event_update:
             return self.crud_event_update.datetime
 
@@ -111,15 +109,13 @@ class ExtensibleModel():
 
     @property
     def created_by(self) -> Optional[models.Model]:
-        """ Determine user who created this object from CRUD log """
-
+        """Determine user who created this object from CRUD log"""
         if self.crud_event_create:
             return self.crud_event_create.user
 
     @property
     def updated_by(self) -> Optional[models.Model]:
-        """ Determine user who last updated this object from CRUD log """
-
+        """Determine user who last updated this object from CRUD log"""
         if self.crud_event_update:
             return self.crud_event_update.user
 
@@ -145,31 +141,27 @@ class ExtensibleModel():
 
     @classmethod
     def property(cls, func: Callable[[], Any], name: Optional[str] = None) -> None:
-        """ Adds the passed callable as a property. """
-
+        """Adds 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. """
-
+        """Adds 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. """
-
+        """Adds 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
+        """Adds 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.
         """
-
         # Force kwargs to be exactly one argument
         if len(kwargs) != 1:
             raise TypeError(f"field() takes 1 keyword argument but {len(kwargs)} were given")
@@ -189,7 +181,7 @@ class ExtensibleModel():
 
 
 class PureDjangoModel(object):
-    """ No-op mixin to mark a model as deliberately not using ExtensibleModel """
+    """No-op mixin to mark a model as deliberately not using ExtensibleModel"""
 
     pass
 
@@ -211,7 +203,7 @@ class _ExtensibleFormMetaclass(ModelFormMetaclass):
 
 
 class ExtensibleForm(ModelForm, metaclass=_ExtensibleFormMetaclass):
-    """ Base model for extensible forms
+    """Base model for extensible forms
 
     This mixin adds functionality which allows
     - apps to add layout nodes to the layout used by django-material
@@ -238,12 +230,11 @@ class ExtensibleForm(ModelForm, metaclass=_ExtensibleFormMetaclass):
         :param node: django-material layout node (Fieldset, Row etc.)
         :type node: LayoutNode
         """
-
         cls.base_layout.append(node)
         cls.layout = Layout(*cls.base_layout)
 
 
 class BaseModelAdmin(GuardedModelAdmin, ObjectPermissionsModelAdmin):
-    """ A base class for ModelAdmin combining django-guardian and rules """
+    """A base class for ModelAdmin combining django-guardian and rules"""
 
     pass
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index bf92167d1dcbbd3d0a805c0542469c6aed16afd4..ea55dfe99dc4e504f8c1274f9155f32ad789e854 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -42,7 +42,7 @@ FIELD_CHOICES = (
 
 
 class Person(ExtensibleModel):
-    """ A model describing any person related to a school, including, but not
+    """A model describing any person related to a school, including, but not
     limited to, students, teachers and guardians (parents).
     """
 
@@ -117,34 +117,30 @@ class Person(ExtensibleModel):
 
     @property
     def primary_group_short_name(self) -> Optional[str]:
-        """ Returns the short_name field of the primary
+        """Returns 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
+        """Sets the primary group related object by
         a short name. It uses the first existing group
         with this short name it can find, creating one
         if it can't find one.
         """
-
         group, created = Group.objects.get_or_create(short_name=value, defaults={"name": value})
         self.primary_group = group
 
     @property
     def full_name(self) -> str:
-        """ Full name of person in last name, first name order """
-
+        """Full name of person in last name, first name order"""
         return f"{self.last_name}, {self.first_name}"
 
     @property
     def adressing_name(self) -> str:
-        """ Full name of person in format configured for addressing """
-
+        """Full name of person in format configured for addressing"""
         if get_site_preferences()["notification__addressing_name_format"] == "last_first":
             return f"{self.last_name}, {self.first_name}"
         elif get_site_preferences()["notification__addressing_name_format"] == "first_last":
@@ -152,13 +148,11 @@ class Person(ExtensibleModel):
 
     @property
     def age(self):
-        """ Age of the person at current time """
-
+        """Age of the person at current time"""
         return self.age_at(timezone.datetime.now().date())
 
     def age_at(self, today):
-        """ Age of the person at a given date and time """
-
+        """Age of the person at a given date and time"""
         years = today.year - self.date_of_birth.year
         if self.date_of_birth.month > today.month or (
             self.date_of_birth.month == today.month and self.date_of_birth.day > today.day
@@ -197,14 +191,13 @@ class Person(ExtensibleModel):
             admin.save()
 
     def auto_select_primary_group(self, pattern: Optional[str] = None, force: bool = False) -> None:
-        """ Auto-select the primary group among the groups the person is member of
+        """Auto-select the primary group among the groups the person is member of
 
         Uses either the pattern passed as argument, or the pattern configured system-wide.
 
         Does not do anything if either no pattern is defined or the user already has
         a primary group, unless force is True.
         """
-
         pattern = pattern or get_site_preferences()["account__primary_group_pattern"]
 
         if pattern:
@@ -213,7 +206,7 @@ class Person(ExtensibleModel):
 
 
 class DummyPerson(Person):
-    """ A dummy person that is not stored into the database.
+    """A dummy person that is not stored into the database.
 
     Used to temporarily inject a Person object into a User.
     """
@@ -230,7 +223,7 @@ class DummyPerson(Person):
 
 
 class AdditionalField(ExtensibleModel):
-    """ An additional field that can be linked to a group """
+    """An additional field that can be linked to a group"""
 
     title = models.CharField(verbose_name=_("Title of field"), max_length=255)
     field_type = models.CharField(
@@ -294,8 +287,7 @@ class Group(ExtensibleModel):
 
     @property
     def announcement_recipients(self):
-        """ Flat list of all members and owners to fulfill announcement API contract """
-
+        """Flat list of all members and owners to fulfill announcement API contract"""
         return list(self.members.all()) + list(self.owners.all())
 
     def __str__(self) -> str:
@@ -317,7 +309,7 @@ class Group(ExtensibleModel):
 
 
 class PersonGroupThrough(ExtensibleModel):
-    """ Through table for many-to-many relationship of group members.
+    """Through table for many-to-many relationship of group members.
 
     It does not have any fields on its own; these are generated upon instantiation
     by inspecting the additional fields selected for the linked group.
@@ -337,7 +329,7 @@ class PersonGroupThrough(ExtensibleModel):
 
 
 class Activity(ExtensibleModel):
-    """ Activity of a user to trace some actions done in AlekSIS in displayable form """
+    """Activity of a user to trace some actions done in AlekSIS in displayable form"""
 
     user = models.ForeignKey(
         "Person", on_delete=models.CASCADE, related_name="activities", verbose_name=_("User")
@@ -357,7 +349,7 @@ class Activity(ExtensibleModel):
 
 
 class Notification(ExtensibleModel):
-    """ Notification to submit to a user """
+    """Notification to submit to a user"""
 
     sender = models.CharField(max_length=100, verbose_name=_("Sender"))
     recipient = models.ForeignKey(
@@ -390,13 +382,12 @@ class Notification(ExtensibleModel):
 
 
 class AnnouncementQuerySet(models.QuerySet):
-    """ Queryset for announcements providing time-based utility functions """
+    """Queryset for announcements providing time-based utility functions"""
 
     def relevant_for(self, obj: Union[models.Model, models.QuerySet]) -> models.QuerySet:
-        """ Get a QuerySet with all announcements relevant for a certain Model (e.g. a Group)
+        """Get a QuerySet with all announcements relevant for a certain Model (e.g. a Group)
         or a set of models in a QuerySet.
         """
-
         if isinstance(obj, models.QuerySet):
             ct = ContentType.objects.get_for_model(obj.model)
             pks = list(obj.values_list("pk", flat=True))
@@ -407,8 +398,7 @@ class AnnouncementQuerySet(models.QuerySet):
         return self.filter(recipients__content_type=ct, recipients__recipient_id__in=pks)
 
     def at_time(self, when: Optional[datetime] = None) -> models.QuerySet:
-        """ Get all announcements at a certain time """
-
+        """Get all announcements at a certain time"""
         when = when or timezone.datetime.now()
 
         # Get announcements by time
@@ -417,8 +407,7 @@ class AnnouncementQuerySet(models.QuerySet):
         return announcements
 
     def on_date(self, when: Optional[date] = None) -> models.QuerySet:
-        """ Get all announcements at a certain date """
-
+        """Get all announcements at a certain date"""
         when = when or timezone.datetime.now().date()
 
         # Get announcements by time
@@ -427,16 +416,14 @@ class AnnouncementQuerySet(models.QuerySet):
         return announcements
 
     def within_days(self, start: date, stop: date) -> models.QuerySet:
-        """ Get all announcements valid for a set of days """
-
+        """Get all announcements valid for a set of days"""
         # Get announcements
         announcements = self.filter(valid_from__date__lte=stop, valid_until__date__gte=start)
 
         return announcements
 
     def for_person(self, person: Person) -> List:
-        """ Get all announcements for one person """
-
+        """Get all announcements for one person"""
         # Filter by person
         announcements_for_person = []
         for announcement in self:
@@ -447,7 +434,7 @@ class AnnouncementQuerySet(models.QuerySet):
 
 
 class Announcement(ExtensibleModel):
-    """ Persistent announcement to display to groups or persons in various places during a
+    """Persistent announcement to display to groups or persons in various places during a
     specific time range.
     """
 
@@ -466,18 +453,16 @@ class Announcement(ExtensibleModel):
 
     @property
     def recipient_persons(self) -> Sequence[Person]:
-        """ Return a list of Persons this announcement is relevant for """
-
+        """Return a list of Persons this announcement is relevant for"""
         persons = []
         for recipient in self.recipients.all():
             persons += recipient.persons
         return persons
 
     def get_recipients_for_model(self, obj: Union[models.Model]) -> Sequence[models.Model]:
-        """ Get all recipients for this announcement
+        """Get all recipients for this announcement
         with a special content type (provided through model)
         """
-
         ct = ContentType.objects.get_for_model(obj)
         return [r.recipient for r in self.recipients.filter(content_type=ct)]
 
@@ -490,7 +475,7 @@ class Announcement(ExtensibleModel):
 
 
 class AnnouncementRecipient(ExtensibleModel):
-    """ Generalisation of a recipient for an announcement, used to wrap arbitrary
+    """Generalisation of a recipient for an announcement, used to wrap arbitrary
     objects that can receive announcements.
 
     Contract: Objects to serve as recipient have a property announcement_recipients
@@ -507,12 +492,11 @@ class AnnouncementRecipient(ExtensibleModel):
 
     @property
     def persons(self) -> Sequence[Person]:
-        """ Return a list of Persons selected by this recipient object
+        """Return a list of Persons selected by this recipient object
 
         If the recipient is a Person, return that object. If not, it returns the list
         from the announcement_recipients field on the target model.
         """
-
         if isinstance(self.recipient, Person):
             return [self.recipient]
         else:
@@ -527,7 +511,7 @@ class AnnouncementRecipient(ExtensibleModel):
 
 
 class DashboardWidget(PolymorphicModel, PureDjangoModel):
-    """ Base class for dashboard widgets on the index page
+    """Base class for dashboard widgets on the index page
 
     To implement a widget, add a model that subclasses DashboardWidget, sets the template
     and implements the get_context method to return a dictionary to be passed as context
@@ -564,8 +548,7 @@ class DashboardWidget(PolymorphicModel, PureDjangoModel):
 
     @staticmethod
     def get_media(widgets: Union[QuerySet, Iterable]):
-        """ Return all media required to render the selected widgets. """
-
+        """Return all media required to render the selected widgets."""
         media = Media()
         for widget in widgets:
             media = media + widget.media
@@ -578,15 +561,13 @@ class DashboardWidget(PolymorphicModel, PureDjangoModel):
     active = models.BooleanField(blank=True, verbose_name=_("Activate Widget"))
 
     def get_context(self):
-        """ Get the context dictionary to pass to the widget template """
-
+        """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 the template to render the widget with. Defaults to the template attribute,
+        """Get the template to render the widget with. Defaults to the template attribute,
         but can be overridden to allow more complex template generation scenarios.
         """
-
         return self.template
 
     def __str__(self):
@@ -598,7 +579,7 @@ class DashboardWidget(PolymorphicModel, PureDjangoModel):
 
 
 class CustomMenu(ExtensibleModel):
-    """ A custom menu to display in the footer """
+    """A custom menu to display in the footer"""
 
     name = models.CharField(max_length=100, verbose_name=_("Menu ID"), unique=True)
 
@@ -607,7 +588,7 @@ class CustomMenu(ExtensibleModel):
 
     @classmethod
     def get_default(cls, name):
-        """ Get a menu by name or create if it does not exist """
+        """Get a menu by name or create if it does not exist"""
         menu, _ = cls.objects.get_or_create(name=name)
         return menu
 
@@ -617,7 +598,7 @@ class CustomMenu(ExtensibleModel):
 
 
 class CustomMenuItem(ExtensibleModel):
-    """ Single item in a custom menu """
+    """Single item in a custom menu"""
 
     menu = models.ForeignKey(
         CustomMenu, models.CASCADE, verbose_name=_("Menu"), related_name="items"
@@ -637,7 +618,7 @@ class CustomMenuItem(ExtensibleModel):
 
 
 class GroupType(ExtensibleModel):
-    """ Descriptive type of a group; used to tag groups and for apps to distinguish
+    """Descriptive type of a group; used to tag groups and for apps to distinguish
     how to display or handle a certain group.
     """
 
@@ -650,7 +631,7 @@ class GroupType(ExtensibleModel):
 
 
 class GlobalPermissions(ExtensibleModel):
-    """ Container for global permissions """
+    """Container for global permissions"""
 
     class Meta:
         managed = False
@@ -667,7 +648,7 @@ class GlobalPermissions(ExtensibleModel):
 
 
 class SitePreferenceModel(PerInstancePreferenceModel, PureDjangoModel):
-    """ Preference model to hold pereferences valid for a site """
+    """Preference model to hold pereferences valid for a site"""
 
     instance = models.ForeignKey(Site, on_delete=models.CASCADE)
 
@@ -676,7 +657,7 @@ class SitePreferenceModel(PerInstancePreferenceModel, PureDjangoModel):
 
 
 class PersonPreferenceModel(PerInstancePreferenceModel, PureDjangoModel):
-    """ Preference model to hold pereferences valid for a person """
+    """Preference model to hold pereferences valid for a person"""
 
     instance = models.ForeignKey(Person, on_delete=models.CASCADE)
 
@@ -685,7 +666,7 @@ class PersonPreferenceModel(PerInstancePreferenceModel, PureDjangoModel):
 
 
 class GroupPreferenceModel(PerInstancePreferenceModel, PureDjangoModel):
-    """ Preference model to hold pereferences valid for members of a group """
+    """Preference model to hold pereferences valid for members of a group"""
 
     instance = models.ForeignKey(Group, on_delete=models.CASCADE)
 
diff --git a/aleksis/core/registries.py b/aleksis/core/registries.py
index cdcd93a687e5c8a1baeb856d556220b511d6ca66..7a0221582b63aa0433b9c6a288ab3d6463fdb502 100644
--- a/aleksis/core/registries.py
+++ b/aleksis/core/registries.py
@@ -1,22 +1,22 @@
-""" Custom registries for some preference containers """
+"""Custom registries for some preference containers"""
 
 from dynamic_preferences.registries import PerInstancePreferenceRegistry
 
 
 class SitePreferenceRegistry(PerInstancePreferenceRegistry):
-    """ Registry for preferences valid for a site """
+    """Registry for preferences valid for a site"""
 
     pass
 
 
 class PersonPreferenceRegistry(PerInstancePreferenceRegistry):
-    """ Registry for preferences valid for a person """
+    """Registry for preferences valid for a person"""
 
     pass
 
 
 class GroupPreferenceRegistry(PerInstancePreferenceRegistry):
-    """ Registry for preferences valid for members of a group """
+    """Registry for preferences valid for members of a group"""
 
     pass
 
diff --git a/aleksis/core/search_indexes.py b/aleksis/core/search_indexes.py
index 7c7beca9e1d691a5548113c37d13a0109c85fe61..397bce3aab0de5ad3a3a20e68774e8eb74ed29c5 100644
--- a/aleksis/core/search_indexes.py
+++ b/aleksis/core/search_indexes.py
@@ -3,12 +3,12 @@ from .util.search import Indexable, SearchIndex
 
 
 class PersonIndex(SearchIndex, Indexable):
-    """ Haystack index for searching persons """
+    """Haystack index for searching persons"""
 
     model = Person
 
 
 class GroupIndex(SearchIndex, Indexable):
-    """ Haystack index for searching groups """
+    """Haystack index for searching groups"""
 
     model = Group
diff --git a/aleksis/core/tables.py b/aleksis/core/tables.py
index 8c99bee43c91b8f8b247754332d641730e9c7c24..74566fc4b2832bcd55c6a85f2537cc91e027dba1 100644
--- a/aleksis/core/tables.py
+++ b/aleksis/core/tables.py
@@ -3,7 +3,7 @@ from django_tables2.utils import A
 
 
 class PersonsTable(tables.Table):
-    """ Table to list persons """
+    """Table to list persons"""
 
     class Meta:
         attrs = {"class": "table table-striped table-bordered table-hover table-responsive-xl"}
@@ -13,7 +13,7 @@ class PersonsTable(tables.Table):
 
 
 class GroupsTable(tables.Table):
-    """ Table to list groups """
+    """Table to list groups"""
 
     class Meta:
         attrs = {"class": "table table-striped table-bordered table-hover table-responsive-xl"}
diff --git a/aleksis/core/tasks.py b/aleksis/core/tasks.py
index 48f73ac0a8ffa00b4e4afd751c73526c8fb5149b..09031dff5cee1e8417fcaf94b4d361af08b32ab5 100644
--- a/aleksis/core/tasks.py
+++ b/aleksis/core/tasks.py
@@ -7,19 +7,17 @@ from .util.notifications import send_notification as _send_notification
 
 @celery_optional
 def send_notification(notification: int, resend: bool = False) -> None:
-    """ Send a notification object to its recipient.
+    """Send a notification object to its recipient.
 
     :param notification: primary key of the notification object to send
     :param resend: Define whether to also send if the notification was already sent
     """
-
     _send_notification(notification, resend)
 
 
 @celery_optional
 def backup_data() -> None:
-    """ Backup database and media using django-dbbackup """
-
+    """Backup database and media using django-dbbackup"""
     # Assemble command-line options for dbbackup management command
     db_options = "-z " * settings.DBBACKUP_COMPRESS_DB + "-e" * settings.DBBACKUP_ENCRYPT_DB
     media_options = (
diff --git a/aleksis/core/templatetags/dashboard.py b/aleksis/core/templatetags/dashboard.py
index b051084f88008a1b30758d46f1d91c9695a408e1..79cf15f23c851e13576546b8c87e6f0fd29562b2 100644
--- a/aleksis/core/templatetags/dashboard.py
+++ b/aleksis/core/templatetags/dashboard.py
@@ -5,8 +5,7 @@ register = Library()
 
 @register.simple_tag
 def include_widget(widget) -> dict:
-    """ Render a template with context from a defined widget """
-
+    """Render a template with context from a defined widget"""
     template = loader.get_template(widget.get_template())
     context = widget.get_context()
 
diff --git a/aleksis/core/templatetags/data_helpers.py b/aleksis/core/templatetags/data_helpers.py
index 0b195d136d86587f892635d6d0e41be1aebada68..5bed2efb95843fcca122d6c507ec67e5b55c848a 100644
--- a/aleksis/core/templatetags/data_helpers.py
+++ b/aleksis/core/templatetags/data_helpers.py
@@ -8,7 +8,6 @@ register = template.Library()
 @register.filter
 def get_dict(value: Any, arg: Any) -> Any:
     """Gets an attribute of an object dynamically from a string name"""
-
     if hasattr(value, str(arg)):
         return getattr(value, arg)
     elif hasattr(value, "keys") and arg in value.keys():
diff --git a/aleksis/core/util/apps.py b/aleksis/core/util/apps.py
index 8d41b2d89f03d3f5eb32a6ad5335507c33951244..33af811d655e7eb35399f12dfb6ce27efc2ac6d6 100644
--- a/aleksis/core/util/apps.py
+++ b/aleksis/core/util/apps.py
@@ -18,8 +18,7 @@ User = get_user_model()
 
 
 class AppConfig(django.apps.AppConfig):
-    """ An extended version of DJango's AppConfig container. """
-
+    """An extended version of DJango's AppConfig container."""
     def ready(self):
         super().ready()
 
@@ -51,14 +50,13 @@ class AppConfig(django.apps.AppConfig):
 
     @classmethod
     def get_name(cls):
-        """ Get name of application package """
-
+        """Get name of application package"""
         return getattr(cls, "verbose_name", cls.name)
         # TODO Try getting from distribution if not set
 
     @classmethod
     def get_version(cls):
-        """ Get version of application package """
+        """Get version of application package"""
         try:
             from .. import __version__  # noqa
         except ImportError:
@@ -68,8 +66,7 @@ class AppConfig(django.apps.AppConfig):
 
     @classmethod
     def get_licence(cls) -> Tuple:
-        """ Get tuple of licence information of application package """
-
+        """Get tuple of licence information of application package"""
         # Get string representation of licence in SPDX format
         licence = getattr(cls, "licence", None)
 
@@ -121,15 +118,13 @@ class AppConfig(django.apps.AppConfig):
 
     @classmethod
     def get_urls(cls):
-        """ Get list of URLs for this application package """
-
+        """Get list of URLs for this application package"""
         return getattr(cls, "urls", {})
         # TODO Try getting from distribution if not set
 
     @classmethod
     def get_copyright(cls) -> Sequence[Tuple[str, str, str]]:
-        """ Get copyright information tuples for application package """
-
+        """Get copyright information tuples for application package"""
         copyrights = getattr(cls, "copyright", tuple())
 
         copyrights_processed = []
@@ -157,7 +152,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
+        """Called on every app instance if a dynamic preference changes, and once on startup
 
         By default, it does nothing.
         """
@@ -173,7 +168,7 @@ class AppConfig(django.apps.AppConfig):
         apps: django.apps.registry.Apps,
         **kwargs,
     ) -> None:
-        """ Called on every app instance before its models are migrated
+        """Called on every app instance before its models are migrated
 
         By default, it does nothing.
         """
@@ -189,7 +184,7 @@ class AppConfig(django.apps.AppConfig):
         apps: django.apps.registry.Apps,
         **kwargs,
     ) -> None:
-        """ Called on every app instance after its models have been migrated
+        """Called on every app instance after its models have been migrated
 
         By default, asks all models to do maintenance on their default data.
         """
@@ -198,7 +193,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
+        """Called after a user logged in
 
         By default, it does nothing.
         """
@@ -207,7 +202,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
+        """Called 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 fc7991a7a16c6365d62b27938e974e2cd1a1fccb..0c44061371fcde86e584f612d9ca5c76b97bba67 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -17,12 +17,11 @@ from django.shortcuts import get_object_or_404
 
 
 def copyright_years(years: Sequence[int], seperator: str = ", ", joiner: str = "–") -> str:
-    """ Takes a sequence of integegers and produces a string with ranges
+    """Takes a sequence of integegers and produces a string with ranges
 
     >>> copyright_years([1999, 2000, 2001, 2005, 2007, 2008, 2009])
     '1999–2001, 2005, 2007–2009'
     """
-
     ranges = [
         list(map(itemgetter(1), group))
         for _, group in groupby(enumerate(years), lambda e: e[1] - e[0])
@@ -36,12 +35,11 @@ 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
+    """Helper to determin if Django debug toolbar should be displayed
 
     Extends the default behaviour by enabling DJDT for superusers independent
     of source IP.
     """
-
     from debug_toolbar.middleware import show_toolbar  # noqa
 
     if not settings.DEBUG:
@@ -56,8 +54,7 @@ def dt_show_toolbar(request: HttpRequest) -> bool:
 
 
 def get_app_packages() -> Sequence[str]:
-    """ Find all packages within the aleksis.apps namespace. """
-
+    """Find all packages within the aleksis.apps namespace."""
     # Import error are non-fatal here because probably simply no app is installed.
     try:
         import aleksis.apps
@@ -70,14 +67,13 @@ def get_app_packages() -> Sequence[str]:
 def merge_app_settings(
     setting: str, original: Union[dict, list], deduplicate: bool = False
 ) -> Union[dict, list]:
-    """ Get a named settings constant from all apps and merge it into the original.
+    """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.
 
     Note: Only selected names will be imported frm it to minimise impact of
     potentially malicious apps!
     """
-
     for pkg in get_app_packages():
         try:
             mod_settings = import_module(pkg + ".settings")
@@ -104,19 +100,17 @@ def merge_app_settings(
 
 
 def get_site_preferences():
-    """ Get the preferences manager of the current site """
-
+    """Get the preferences manager of the current site"""
     from django.contrib.sites.models import Site  # noqa
 
     return Site.objects.get_current().preferences
 
 
 def lazy_preference(section: str, name: str) -> Callable[[str, str], Any]:
-    """ Lazily get a config value from dynamic preferences. Useful to bind preferences
+    """Lazily get a config value from dynamic preferences. Useful to bind preferences
     to other global settings to make them available to third-party apps that are not
     aware of dynamic preferences.
     """
-
     def _get_preference(section: str, name: str) -> Any:
         return get_site_preferences()[f"{section}__{name}"]
 
@@ -128,8 +122,7 @@ def lazy_preference(section: str, name: str) -> Callable[[str, str], Any]:
 def lazy_get_favicon_url(
     title: str, size: int, rel: str, default: Optional[str] = None
 ) -> Callable[[str, str], Any]:
-    """ Lazily get the URL to a favicon image """
-
+    """Lazily get the URL to a favicon image"""
     def _get_favicon_url(size: int, rel: str) -> Any:
         from favicon.models import Favicon  # noqa
 
@@ -144,8 +137,7 @@ def lazy_get_favicon_url(
 
 
 def is_impersonate(request: HttpRequest) -> bool:
-    """ Check whether the user was impersonated by an admin """
-
+    """Check whether the user was impersonated by an admin"""
     if hasattr(request, "user"):
         return getattr(request.user, "is_impersonate", False)
     else:
@@ -153,11 +145,10 @@ def is_impersonate(request: HttpRequest) -> bool:
 
 
 def has_person(obj: Union[HttpRequest, Model]) -> bool:
-    """ Check wehether a model object has a person attribute linking it to a Person
+    """Check wehether a model object has a person attribute linking it to a Person
     object. The passed object can also be a HttpRequest object, in which case its
     associated User object is unwrapped and tested.
     """
-
     if isinstance(obj, HttpRequest):
         if hasattr(obj, "user"):
             obj = obj.user
@@ -174,13 +165,12 @@ def has_person(obj: Union[HttpRequest, Model]) -> bool:
 
 
 def celery_optional(orig: Callable) -> Callable:
-    """ Decorator that makes Celery optional for a function.
+    """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
     and it is executed synchronously.
     """
-
     if hasattr(settings, "CELERY_RESULT_BACKEND"):
         from ..celery import app  # noqa
 
@@ -196,8 +186,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 """
-
+    """Updates 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
@@ -211,8 +200,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 """
-
+    """Provides custom information in all templates"""
     from ..models import CustomMenu
 
     return {
@@ -221,15 +209,14 @@ def custom_information_processor(request: HttpRequest) -> dict:
 
 
 def now_tomorrow() -> datetime:
-    """ Return current time tomorrow """
+    """Return current time tomorrow"""
     return timezone.now() + timedelta(days=1)
 
 
 def objectgetter_optional(
     model: Model, default: Optional[Any] = None, default_eval: bool = False
 ) -> Callable[[HttpRequest, Optional[int]], Model]:
-    """ Get an object by pk, defaulting to None """
-
+    """Get an object by pk, defaulting to None"""
     def get_object(request: HttpRequest, id_: Optional[int] = None) -> Model:
         if id_ is not None:
             return get_object_or_404(model, pk=id_)
diff --git a/aleksis/core/util/messages.py b/aleksis/core/util/messages.py
index 4a6d2d4308a5009f6bfee6ea8a9c85f771b2f655..57a137507b48820fafd4199eb3deb18d8c1861c6 100644
--- a/aleksis/core/util/messages.py
+++ b/aleksis/core/util/messages.py
@@ -8,12 +8,11 @@ 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 to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to DEBUG level.
-    """
-
+   """
     if request:
         return messages.add_message(request, level, message, **kwargs)
     else:
@@ -21,50 +20,45 @@ 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 message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to DEBUG level.
-    """
-
+   """
     return add_message(request, messages.DEBUG, message, **kwargs)
 
 
 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 message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to INFO level.
-    """
-
+   """
     return add_message(request, messages.INFO, message, **kwargs)
 
 
 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 message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to SUCCESS level.
-    """
-
+   """
     return add_message(request, messages.SUCCESS, message, **kwargs)
 
 
 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 message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to WARNING level.
-    """
-
+   """
     return add_message(request, messages.WARNING, message, **kwargs)
 
 
 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 a message to either Django's message framework, if called from a web request,
     or to the default logger.
 
     Default to ERROR level.
-    """
-
+   """
     return add_message(request, messages.ERROR, message, **kwargs)
diff --git a/aleksis/core/util/middlewares.py b/aleksis/core/util/middlewares.py
index fc86082ececa88da0384ec8fcd987aa08b638648..7ac5e5f2cbb710d3c6bb8c1bdda83ca170c96165 100644
--- a/aleksis/core/util/middlewares.py
+++ b/aleksis/core/util/middlewares.py
@@ -7,7 +7,7 @@ from .core_helpers import has_person
 
 
 class EnsurePersonMiddleware:
-    """ Middleware that ensures that the logged-in user is linked to a person.
+    """Middleware that ensures that the logged-in user is linked to a person.
 
     It is needed to inject a dummy person to a superuser that would otherwise
     not have an associated person, in order they can get their account set up
diff --git a/aleksis/core/util/notifications.py b/aleksis/core/util/notifications.py
index fd294e5a1b5368929c40cc16c1187f6d671a3bb3..9698841d062e8428ba8c922681d665bae77abeb3 100644
--- a/aleksis/core/util/notifications.py
+++ b/aleksis/core/util/notifications.py
@@ -1,4 +1,4 @@
-""" Utility code for notification system """
+"""Utility code for notification system"""
 
 from typing import Sequence, Union
 
@@ -22,8 +22,7 @@ except ImportError:
 def send_templated_sms(
     template_name: str, from_number: str, recipient_list: Sequence[str], context: dict
 ) -> None:
-    """ Render a plan-text template and send via SMS to all recipients. """
-
+    """Render a plan-text template and send via SMS to all recipients."""
     template = get_template(template_name)
     text = template.render(context)
 
@@ -70,12 +69,11 @@ _CHANNELS_MAP = {
 
 
 def send_notification(notification: Union[int, "Notification"], resend: bool = False) -> None:
-    """ Send a notification through enabled channels.
+    """Send a notification through enabled channels.
 
     If resend is passed as True, the notification is sent even if it was
     previously marked as sent.
     """
-
     channels = lazy_preference("notification", "channels")
 
     if isinstance(notification, int):
@@ -90,13 +88,12 @@ def send_notification(notification: Union[int, "Notification"], resend: bool = F
 
 
 def get_notification_choices() -> list:
-    """ Return all available channels for notifications.
+    """Return all available channels for notifications.
 
     This gathers the channels that are technically available as per the
     system configuration. Which ones are available to users is defined
     by the administrator (by selecting a subset of these choices).
     """
-
     choices = []
     for channel, (name, check, send) in _CHANNELS_MAP.items():
         if check():
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
index d76df8310eac7cfbeae2bb60b846f4092dbc9d4f..ceb03c68c0619bef76aee1a9439a40bfb9078cc5 100644
--- a/aleksis/core/util/predicates.py
+++ b/aleksis/core/util/predicates.py
@@ -12,28 +12,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 """
-
+    """Checks 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 """
-
+    """Checks 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 """
-
+    """Checks 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 """
-
+    """Builds predicate which checks whether a user has a global permission"""
     name = f"has_global_perm:{perm}"
 
     @predicate(name)
@@ -44,8 +40,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 """
-
+    """Builds predicate which checks whether a user has a permission on a object"""
     name = f"has_global_perm:{perm}"
 
     @predicate(name)
@@ -58,10 +53,9 @@ def has_object_perm(perm: str):
 
 
 def has_any_object(perm: str, klass):
-    """ Build predicate which checks whether a user has access
+    """Build predicate which checks whether a user has access
     to objects with the provided permission
     """
-
     name = f"has_any_object:{perm}"
 
     @predicate(name)
@@ -74,29 +68,25 @@ def has_any_object(perm: str, klass):
 
 @predicate
 def has_person(user: User) -> bool:
-    """ Predicate which checks whether a user has a linked person """
-
+    """Predicate which checks whether a user has a linked person"""
     return has_person_helper(user)
 
 
 @predicate
 def is_current_person(user: User, obj: Model) -> bool:
-    """ Predicate which checks if the provided object is the person linked to the user object """
-
+    """Predicate which checks if the provided object is the person linked to the user object"""
     return user.person == obj
 
 
 @predicate
 def is_group_owner(user: User, group: Group) -> bool:
-    """ Predicate which checks if the user is a owner of the provided group """
-
+    """Predicate which checks if the user is a owner of the provided group"""
     return group.owners.filter(owners=user.person).exists()
 
 
 @predicate
 def is_notification_recipient(user: User, obj: Model) -> bool:
-    """ Predicate which checks whether the recipient of the
+    """Predicate which checks whether the recipient of the
     notification a user wants to mark read is this user
     """
-
     return user == obj.recipient.user
diff --git a/aleksis/core/util/sass_helpers.py b/aleksis/core/util/sass_helpers.py
index d624944c9b3a30fab843682f897c100e4dd4edc7..c28d037e17d0184506f7fb3fd21819fb7cb3aef6 100644
--- a/aleksis/core/util/sass_helpers.py
+++ b/aleksis/core/util/sass_helpers.py
@@ -1,4 +1,4 @@
-""" Helpers for SASS/SCSS compilation """
+"""Helpers for SASS/SCSS compilation"""
 
 import os
 from glob import glob
@@ -12,8 +12,7 @@ from .core_helpers import get_site_preferences
 
 
 def get_colour(html_colour: str) -> SassColor:
-    """ Get a SASS colour object from an HTML colour string """
-
+    """Get a SASS colour object from an HTML colour string"""
     rgb = web2hex(html_colour, force_long=True)[1:]
     r, g, b = int(rgb[0:2], 16), int(rgb[2:4], 16), int(rgb[4:6], 16)
 
@@ -21,14 +20,12 @@ def get_colour(html_colour: str) -> SassColor:
 
 
 def get_preference(section: str, name: str) -> str:
-    """ Get a preference from dynamic-preferences """
-
+    """Get a preference from dynamic-preferences"""
     return get_site_preferences()[f"{section}__{name}"]
 
 
 def clean_scss(*args, **kwargs) -> None:
-    """ Unlink compiled CSS (i.e. cache invalidation) """
-
+    """Unlink compiled CSS (i.e. cache invalidation)"""
     for source_map in glob(os.path.join(settings.STATIC_ROOT, "*.css.map")):
         try:
             os.unlink(source_map)
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index 49594d64721d0cd27216df529fb4f8e46b95b028..cfe22442f3109ba8280abc5360efb9001a931d68 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -41,8 +41,7 @@ from .util.core_helpers import objectgetter_optional
 
 @permission_required("core.view_dashboard")
 def index(request: HttpRequest) -> HttpResponse:
-    """ Dashboard """
-
+    """Dashboard"""
     context = {}
 
     activities = request.user.person.activities.all()[:5]
@@ -66,14 +65,12 @@ def index(request: HttpRequest) -> HttpResponse:
 
 
 def offline(request: HttpRequest) -> HttpResponse:
-    """ Offline message for PWA """
-
+    """Offline message for PWA"""
     return render(request, "core/offline.html")
 
 
 def about(request: HttpRequest) -> HttpResponse:
-    """ About page listing all apps """
-
+    """About page listing all apps"""
     context = {}
 
     context["app_configs"] = list(
@@ -85,8 +82,7 @@ def about(request: HttpRequest) -> HttpResponse:
 
 @permission_required("core.view_persons")
 def persons(request: HttpRequest) -> HttpResponse:
-    """ List view listing all persons """
-
+    """List view listing all persons"""
     context = {}
 
     # Get all persons
@@ -106,8 +102,7 @@ def persons(request: HttpRequest) -> HttpResponse:
     "core.view_person", fn=objectgetter_optional(Person, "request.user.person", True)
 )
 def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """ Detail view for one person; defaulting to logged-in person """
-
+    """Detail view for one person; defaulting to logged-in person"""
     context = {}
 
     person = objectgetter_optional(Person, "request.user.person", True)(request, id_)
@@ -126,8 +121,7 @@ def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
 
 @permission_required("core.view_group", fn=objectgetter_optional(Group, None, False))
 def group(request: HttpRequest, id_: int) -> HttpResponse:
-    """ Detail view for one group """
-
+    """Detail view for one group"""
     context = {}
 
     group = objectgetter_optional(Group, None, False)(request, id_)
@@ -157,8 +151,7 @@ def group(request: HttpRequest, id_: int) -> HttpResponse:
 
 @permission_required("core.view_groups")
 def groups(request: HttpRequest) -> HttpResponse:
-    """ List view for listing all groups """
-
+    """List view for listing all groups"""
     context = {}
 
     # Get all groups
@@ -174,8 +167,7 @@ def groups(request: HttpRequest) -> HttpResponse:
 
 @permission_required("core.link_persons_accounts")
 def persons_accounts(request: HttpRequest) -> HttpResponse:
-    """ View allowing to batch-process linking of users to persons """
-
+    """View allowing to batch-process linking of users to persons"""
     context = {}
 
     # Get all persons
@@ -195,8 +187,7 @@ def persons_accounts(request: HttpRequest) -> HttpResponse:
 
 @permission_required("core.assign_child_groups_to_groups")
 def groups_child_groups(request: HttpRequest) -> HttpResponse:
-    """ View for batch-processing assignment from child groups to groups """
-
+    """View for batch-processing assignment from child groups to groups"""
     context = {}
 
     # Apply filter
@@ -235,8 +226,7 @@ def groups_child_groups(request: HttpRequest) -> HttpResponse:
     "core.edit_person", fn=objectgetter_optional(Person, "request.user.person", True)
 )
 def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """ Edit view for a single person, defaulting to logged-in person """
-
+    """Edit view for a single person, defaulting to logged-in person"""
     context = {}
 
     person = objectgetter_optional(Person, "request.user.person", True)(request, id_)
@@ -266,8 +256,7 @@ def get_group_by_id(request: HttpRequest, id_: Optional[int] = None):
 
 @permission_required("core.edit_group", fn=objectgetter_optional(Group, None, False))
 def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """ View to edit or create a group """
-
+    """View to edit or create a group"""
     context = {}
 
     group = objectgetter_optional(Group, None, False)(request, id_)
@@ -295,16 +284,14 @@ def edit_group(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
 
 @permission_required("core.manage_data")
 def data_management(request: HttpRequest) -> HttpResponse:
-    """ View with special menu for data management """
-
+    """View with special menu for data management"""
     context = {}
     return render(request, "core/data_management.html", context)
 
 
 @permission_required("core.view_system_status")
 def system_status(request: HttpRequest) -> HttpResponse:
-    """ View giving information about the system status """
-
+    """View giving information about the system status"""
     context = {}
 
     return render(request, "core/system_status.html", context)
@@ -314,8 +301,7 @@ def system_status(request: HttpRequest) -> HttpResponse:
     "core.mark_notification_as_read", fn=objectgetter_optional(Notification, None, False)
 )
 def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse:
-    """ Mark a notification read """
-
+    """Mark a notification read"""
     notification = objectgetter_optional(Notification, None, False)(request, id_)
 
     notification.read = True
@@ -327,8 +313,7 @@ def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse:
 
 @permission_required("core.view_announcements")
 def announcements(request: HttpRequest) -> HttpResponse:
-    """ List view of announcements """
-
+    """List view of announcements"""
     context = {}
 
     # Get all announcements
@@ -342,8 +327,7 @@ def announcements(request: HttpRequest) -> HttpResponse:
     "core.create_or_edit_announcement", fn=objectgetter_optional(Announcement, None, False)
 )
 def announcement_form(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """ View to create or edit an announcement """
-
+    """View to create or edit an announcement"""
     context = {}
 
     announcement = objectgetter_optional(Announcement, None, False)(request, id_)
@@ -373,8 +357,7 @@ def announcement_form(request: HttpRequest, id_: Optional[int] = None) -> HttpRe
     "core.delete_announcement", fn=objectgetter_optional(Announcement, None, False)
 )
 def delete_announcement(request: HttpRequest, id_: int) -> HttpResponse:
-    """ View to delete an announcement """
-
+    """View to delete an announcement"""
     if request.method == "POST":
         announcement = objectgetter_optional(Announcement, None, False)(request, id_)
         announcement.delete()
@@ -385,8 +368,7 @@ def delete_announcement(request: HttpRequest, id_: int) -> HttpResponse:
 
 @permission_required("core.search")
 def searchbar_snippets(request: HttpRequest) -> HttpResponse:
-    """ View to return HTML snippet with searchbar autocompletion results """
-
+    """View to return HTML snippet with searchbar autocompletion results"""
     query = request.GET.get("q", "")
     limit = int(request.GET.get("limit", "5"))
 
@@ -397,8 +379,7 @@ def searchbar_snippets(request: HttpRequest) -> HttpResponse:
 
 
 class PermissionSearchView(PermissionRequiredMixin, SearchView):
-    """ Wrapper to apply permission to haystack's search view """
-
+    """Wrapper to apply permission to haystack's search view"""
     permission_required = "core.search"
 
     def create_response(self):
@@ -414,8 +395,7 @@ def preferences(
     pk: Optional[int] = None,
     section: Optional[str] = None,
 ) -> HttpResponse:
-    """ View for changing preferences """
-
+    """View for changing preferences"""
     context = {}
 
     # Decide which registry to use and check preferences