diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7d0becf27..5bd57ab9c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,7 +5,7 @@ jobs:
     runs-on: ubuntu-latest
     services:
       postgres:
-        image: postgres:10.1
+        image: postgres:15.3
         env:
           POSTGRES_USER: postgres
           POSTGRES_PASSWORD: postgres
diff --git a/banners/__init__.py b/banners/__init__.py
index 010b54570..e69de29bb 100644
--- a/banners/__init__.py
+++ b/banners/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'banners.apps.BannersAppConfig'
diff --git a/base-requirements.txt b/base-requirements.txt
index 07f0f5a3f..a86bf74ae 100644
--- a/base-requirements.txt
+++ b/base-requirements.txt
@@ -1,10 +1,10 @@
 dj-database-url==0.5.0
-django-pipeline==2.0.6
-django-sitetree==1.18.0
+django-pipeline==3.0.0  # 3.0.0 is first version that supports Django 4.2
+django-sitetree==1.18.0  # >=1.17.1 is (?) first version that supports Django 4.2
 django-apptemplates==1.5
 django-admin-interface==0.24.2
 django-translation-aliases==0.1.0
-Django==2.2.28
+Django==4.2.16
 docutils==0.12
 Markdown==3.3.4
 cmarkgfm==0.6.0
@@ -22,32 +22,31 @@ chardet==4.0.0
 celery[redis]==5.3.6
 django-celery-beat==2.5.0
 # TODO: We may drop 'django-imagekit' completely.
-django-imagekit==4.0.2
+django-imagekit==5.0  # 5.0 is first version that supports Django 4.2
 django-haystack==3.2.1
 elasticsearch>=7,<8
 # TODO: 0.14.0 only supports Django 1.8 and 1.11.
-django-tastypie==0.14.3
+django-tastypie==0.14.6  # 0.14.6 is first version that supports Django 4.2
 
 pytz==2021.1
 python-dateutil==2.8.2
 
 requests[security]>=2.26.0
 
-django-honeypot==1.0.1
-django-markupfield==2.0.0
-django-markupfield-helpers==0.1.1
+django-honeypot==1.0.4  # 1.0.4 is first version that supports Django 4.2
+django-markupfield==2.0.1
 
-django-allauth==0.50.0
+django-allauth==0.57.2 # 0.55.0 is first version that supports Django 4.2
 
 django-waffle==2.2.1
 
-djangorestframework==3.12.2
+djangorestframework==3.14.0  # 3.14.0 is first version that supports Django 4.1, 4.2 support hasnt been "released"
 django-filter==2.4.0
 django-ordered-model==3.4.3
 django-widget-tweaks==1.4.8
 django-countries==7.2.1
 num2words==0.5.10
-django-polymorphic==3.0.0
+django-polymorphic==3.1.0  # 3.1.0 is first version that supports Django 4.0, unsure if it fully supports 4.2
 sorl-thumbnail==12.7.0
 django-extensions==3.1.4
 django-import-export==2.7.1
diff --git a/blogs/__init__.py b/blogs/__init__.py
index 620291c46..e69de29bb 100644
--- a/blogs/__init__.py
+++ b/blogs/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'blogs.apps.BlogsAppConfig'
diff --git a/blogs/admin.py b/blogs/admin.py
index 055431ae9..e5fea1cfb 100644
--- a/blogs/admin.py
+++ b/blogs/admin.py
@@ -10,11 +10,13 @@ class BlogEntryAdmin(admin.ModelAdmin):
     date_hierarchy = 'pub_date'
     actions = ['sync_new_entries']
 
+    @admin.action(
+        description="Sync new blog entries"
+    )
     def sync_new_entries(self, request, queryset):
         call_command('update_blogs')
         self.message_user(request, "Blog entries updated.")
 
-    sync_new_entries.short_description = "Sync new blog entries"
 
 
 @admin.register(FeedAggregate)
diff --git a/blogs/migrations/0003_alter_relatedblog_creator_and_more.py b/blogs/migrations/0003_alter_relatedblog_creator_and_more.py
new file mode 100644
index 000000000..9e71084a8
--- /dev/null
+++ b/blogs/migrations/0003_alter_relatedblog_creator_and_more.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('blogs', '0002_remove_translations_and_contributors'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='relatedblog',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='relatedblog',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/blogs/parser.py b/blogs/parser.py
index 8ac8dc684..fd5e4b54d 100644
--- a/blogs/parser.py
+++ b/blogs/parser.py
@@ -3,7 +3,7 @@
 
 from django.conf import settings
 from django.template.loader import render_to_string
-from django.utils.timezone import make_aware, utc
+from django.utils.timezone import make_aware
 
 from boxes.models import Box
 from .models import BlogEntry, Feed
@@ -16,7 +16,7 @@ def get_all_entries(feed_url):
 
     for e in d['entries']:
         published = make_aware(
-            datetime.datetime(*e['published_parsed'][:7]), timezone=utc
+            datetime.datetime(*e['published_parsed'][:7]), timezone=datetime.timezone.utc
         )
 
         entry = {
diff --git a/boxes/__init__.py b/boxes/__init__.py
index 401a83d2e..e69de29bb 100644
--- a/boxes/__init__.py
+++ b/boxes/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'boxes.apps.BoxesAppConfig'
diff --git a/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py b/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py
new file mode 100644
index 000000000..3829382ec
--- /dev/null
+++ b/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('boxes', '0003_auto_20171101_2138'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='box',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='box',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/cms/__init__.py b/cms/__init__.py
index 92d29195c..e69de29bb 100644
--- a/cms/__init__.py
+++ b/cms/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'cms.apps.CmsAppConfig'
diff --git a/codesamples/__init__.py b/codesamples/__init__.py
index f51a992fa..e69de29bb 100644
--- a/codesamples/__init__.py
+++ b/codesamples/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'codesamples.apps.CodesamplesAppConfig'
diff --git a/codesamples/migrations/0004_alter_codesample_creator_and_more.py b/codesamples/migrations/0004_alter_codesample_creator_and_more.py
new file mode 100644
index 000000000..0b29294ad
--- /dev/null
+++ b/codesamples/migrations/0004_alter_codesample_creator_and_more.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('codesamples', '0003_auto_20170821_2000'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='codesample',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='codesample',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/codesamples/tests.py b/codesamples/tests.py
index 73c85c164..7ddf51119 100644
--- a/codesamples/tests.py
+++ b/codesamples/tests.py
@@ -16,9 +16,7 @@ def setUp(self):
             is_published=False)
 
     def test_published(self):
-        self.assertQuerysetEqual(CodeSample.objects.published(),
-                                 ['<CodeSample: Copy One>'])
+        self.assertQuerySetEqual(CodeSample.objects.published(),['<CodeSample: Copy One>'], transform=repr)
 
     def test_draft(self):
-        self.assertQuerysetEqual(CodeSample.objects.draft(),
-                                 ['<CodeSample: Copy Two>'])
+        self.assertQuerySetEqual(CodeSample.objects.draft(),['<CodeSample: Copy Two>'], transform=repr)
diff --git a/community/__init__.py b/community/__init__.py
index bc11cfaf6..e69de29bb 100644
--- a/community/__init__.py
+++ b/community/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'community.apps.CommunityAppConfig'
diff --git a/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py b/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py
new file mode 100644
index 000000000..9372dbf0e
--- /dev/null
+++ b/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py
@@ -0,0 +1,76 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('community', '0001_squashed_0004_auto_20170831_0541'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='link',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='link',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='link',
+            name='post',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='related_%(class)s', to='community.post'),
+        ),
+        migrations.AlterField(
+            model_name='photo',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='photo',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='photo',
+            name='post',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='related_%(class)s', to='community.post'),
+        ),
+        migrations.AlterField(
+            model_name='post',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='post',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='post',
+            name='meta',
+            field=models.JSONField(blank=True, default=dict),
+        ),
+        migrations.AlterField(
+            model_name='video',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='video',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='video',
+            name='post',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='related_%(class)s', to='community.post'),
+        ),
+    ]
diff --git a/community/models.py b/community/models.py
index 1e199b590..75ee94cd8 100644
--- a/community/models.py
+++ b/community/models.py
@@ -1,4 +1,4 @@
-from django.contrib.postgres.fields import JSONField
+from django.db.models import JSONField
 from django.urls import reverse
 from django.db import models
 from django.utils.translation import gettext_lazy as _
diff --git a/community/tests/test_managers.py b/community/tests/test_managers.py
index 004e5ee2e..8e91e5523 100644
--- a/community/tests/test_managers.py
+++ b/community/tests/test_managers.py
@@ -16,6 +16,6 @@ def test_post_manager(self):
             status=Post.STATUS_PUBLIC
         )
 
-        self.assertQuerysetEqual(Post.objects.all(), [public_post, private_post], lambda x: x)
-        self.assertQuerysetEqual(Post.objects.public(), [public_post], lambda x: x)
-        self.assertQuerysetEqual(Post.objects.private(), [private_post], lambda x: x)
+        self.assertQuerySetEqual(Post.objects.all(), [public_post, private_post], lambda x: x)
+        self.assertQuerySetEqual(Post.objects.public(), [public_post], lambda x: x)
+        self.assertQuerySetEqual(Post.objects.private(), [private_post], lambda x: x)
diff --git a/companies/__init__.py b/companies/__init__.py
index 1a15cc943..e69de29bb 100644
--- a/companies/__init__.py
+++ b/companies/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'companies.apps.CompaniesAppConfig'
diff --git a/docker-compose.yml b/docker-compose.yml
index 2e5f8bf16..4406c0ff5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,7 +2,7 @@ version: "3.9"
 
 services:
   postgres:
-    image: postgres:10-bullseye
+    image: postgres:15.3-bullseye
     ports:
       - "5433:5432"
     environment:
diff --git a/downloads/__init__.py b/downloads/__init__.py
index 0f460f952..e69de29bb 100644
--- a/downloads/__init__.py
+++ b/downloads/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'downloads.apps.DownloadsAppConfig'
diff --git a/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py b/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py
new file mode 100644
index 000000000..368d575c2
--- /dev/null
+++ b/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py
@@ -0,0 +1,46 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('downloads', '0010_releasefile_sbom_spdx2_file'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='os',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='os',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='release',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='release',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='releasefile',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='releasefile',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/downloads/tests/test_views.py b/downloads/tests/test_views.py
index 50270c556..e495b9e93 100644
--- a/downloads/tests/test_views.py
+++ b/downloads/tests/test_views.py
@@ -41,7 +41,7 @@ def test_download_release_detail(self):
         self.assertEqual(response.status_code, 200)
 
         with self.subTest("Release file sizes should be human-readable"):
-            self.assertInHTML("<td>11.8 MB</td>", response.content.decode())
+            self.assertInHTML("<td>11.8&nbsp;MB</td>", response.content.decode())
 
         url = reverse('download:download_release_detail', kwargs={'release_slug': 'fake_slug'})
         response = self.client.get(url)
@@ -122,7 +122,7 @@ def test_invalid_token(self):
         self.assertEqual(response.status_code, 401)
 
         url = self.create_url('os')
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization_invalid)
+        response = self.client.get(url, headers={"authorization": self.Authorization_invalid})
         # TODO: API v1 returns 200 for a GET request even if token is invalid.
         # 'StaffAuthorization.read_list` returns 'object_list' unconditionally,
         # and 'StaffAuthorization.read_detail` returns 'True'.
@@ -222,7 +222,7 @@ def test_get_release(self):
         self.assertEqual(len(content), 4)
 
         # Login to get all releases.
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
         content = self.get_json(response)
         self.assertEqual(len(content), 5)
@@ -258,7 +258,7 @@ def test_post_release(self):
         response = self.client.get(new_url)
         # TODO: API v1 returns 401; and API v2 returns 404.
         self.assertIn(response.status_code, [401, 404])
-        response = self.client.get(new_url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(new_url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
         content = self.get_json(response)
         self.assertEqual(content['name'], data['name'])
@@ -490,15 +490,15 @@ def test_throttling_anon(self):
     )
     def test_throttling_user(self):
         url = self.create_url('os')
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
 
         # Second request should be okay for a user.
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
 
         # Third request should return '429 TOO MANY REQUESTS'.
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 429)
 
     def test_filter_release_file_delete_by_release(self):
@@ -552,6 +552,6 @@ def test_filter_release_file_delete_by_release(self):
                 'release_file/delete_by_release',
                 filters={'release': self.release_275.pk},
             ),
-            HTTP_AUTHORIZATION=self.Authorization,
+            headers={"authorization": self.Authorization}
         )
         self.assertEqual(response.status_code, 405)
diff --git a/events/__init__.py b/events/__init__.py
index 28291bff9..e69de29bb 100644
--- a/events/__init__.py
+++ b/events/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'events.apps.EventsAppConfig'
diff --git a/events/importer.py b/events/importer.py
index fa303184b..e47775060 100644
--- a/events/importer.py
+++ b/events/importer.py
@@ -48,12 +48,13 @@ def import_event(self, event_data):
         )
         defaults = {
             'title': title,
-            'description': description,
-            'description_markup_type': 'html',
             'venue': location,
             'calendar': self.calendar,
         }
         event, _ = Event.objects.update_or_create(uid=uid, defaults=defaults)
+        event.description.raw = description
+        event.description.markup_type = "html"
+        event.save()
         self.import_occurrence(event, event_data)
 
     def fetch(self, url):
diff --git a/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py b/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py
new file mode 100644
index 000000000..371ae3aae
--- /dev/null
+++ b/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py
@@ -0,0 +1,46 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('events', '0007_auto_20180705_0352'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='alarm',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='alarm',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='calendar',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='calendar',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='event',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='event',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/jobs/__init__.py b/jobs/__init__.py
index 3716a978d..e69de29bb 100644
--- a/jobs/__init__.py
+++ b/jobs/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'jobs.apps.JobsAppConfig'
diff --git a/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py b/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py
new file mode 100644
index 000000000..a82f65ac9
--- /dev/null
+++ b/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py
@@ -0,0 +1,36 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('jobs', '0020_auto_20191101_1601'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='job',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='job',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='jobreviewcomment',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='jobreviewcomment',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/jobs/signals.py b/jobs/signals.py
index 9c470d83a..0317ff716 100644
--- a/jobs/signals.py
+++ b/jobs/signals.py
@@ -1,10 +1,10 @@
 from django.dispatch import Signal
 
 # Sent after job offer was submitted for review
-job_was_submitted = Signal(providing_args=['job'])
+job_was_submitted = Signal()
 # Sent after job offer was approved
-job_was_approved = Signal(providing_args=['approving_user', 'job'])
+job_was_approved = Signal()
 # Sent after job offer was rejected
-job_was_rejected = Signal(providing_args=['rejecting_user', 'job'])
+job_was_rejected = Signal()
 # Sent after comment was posted
-comment_was_posted = Signal(providing_args=['comment'])
+comment_was_posted = Signal()
diff --git a/mailing/tests/__init__.py b/mailing/tests/__init__.py
index d85108ab5..8d8b4f5c7 100644
--- a/mailing/tests/__init__.py
+++ b/mailing/tests/__init__.py
@@ -1 +1 @@
-# Create your tests here
+"""Tests for the mailing app."""
diff --git a/mailing/tests/forms.py b/mailing/tests/forms.py
new file mode 100644
index 000000000..b433adea6
--- /dev/null
+++ b/mailing/tests/forms.py
@@ -0,0 +1,13 @@
+"""Forms to be used in mailing tests."""
+
+from mailing.forms import BaseEmailTemplateForm
+from mailing.tests.models import MockEmailTemplate
+
+
+class TestBaseEmailTemplateForm(BaseEmailTemplateForm):
+    """Base email template form for testing."""
+
+    class Meta:
+        """Metaclass for the form."""
+        model = MockEmailTemplate
+        fields = "__all__"
diff --git a/mailing/tests/models.py b/mailing/tests/models.py
new file mode 100644
index 000000000..917e8dfb9
--- /dev/null
+++ b/mailing/tests/models.py
@@ -0,0 +1,12 @@
+"""Models to be used in mailing tests."""
+
+from mailing.models import BaseEmailTemplate
+
+
+class MockEmailTemplate(BaseEmailTemplate):
+    """Mock model for BaseEmailTemplate to use in tests."""
+
+    class Meta:
+        """Metaclass for MockEmailTemplate to avoid creating a table in the database."""
+        app_label = 'mailing'
+        managed = False
diff --git a/mailing/tests/test_forms.py b/mailing/tests/test_forms.py
index 1e9165a0c..f7a0c6890 100644
--- a/mailing/tests/test_forms.py
+++ b/mailing/tests/test_forms.py
@@ -1,6 +1,7 @@
+"""Tests for mailing app forms."""
 from django.test import TestCase
 
-from mailing.forms import BaseEmailTemplateForm
+from mailing.tests.forms import TestBaseEmailTemplateForm
 
 
 class BaseEmailTemplateFormTests(TestCase):
@@ -14,16 +15,16 @@ def setUp(self):
 
     def test_validate_required_fields(self):
         required = set(self.data)
-        form = BaseEmailTemplateForm(data={})
+        form = TestBaseEmailTemplateForm(data={})
         self.assertFalse(form.is_valid())
         self.assertEqual(required, set(form.errors))
 
     def test_validate_with_correct_data(self):
-        form = BaseEmailTemplateForm(data=self.data)
+        form = TestBaseEmailTemplateForm(data=self.data)
         self.assertTrue(form.is_valid())
 
     def test_invalid_form_if_broken_template_syntax(self):
         self.data["content"] = "Invalid syntax {% invalid %}"
-        form = BaseEmailTemplateForm(data=self.data)
+        form = TestBaseEmailTemplateForm(data=self.data)
         self.assertFalse(form.is_valid())
         self.assertIn("content", form.errors, form.errors)
diff --git a/membership/__init__.py b/membership/__init__.py
index 2e00144a5..e69de29bb 100644
--- a/membership/__init__.py
+++ b/membership/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'membership.apps.MembershipAppConfig'
diff --git a/minutes/__init__.py b/minutes/__init__.py
index 862de63c6..e69de29bb 100644
--- a/minutes/__init__.py
+++ b/minutes/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'minutes.apps.MinutesAppConfig'
diff --git a/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py b/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py
new file mode 100644
index 000000000..07e512874
--- /dev/null
+++ b/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('minutes', '0002_auto_20150416_1853'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='minutes',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='minutes',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/minutes/tests/test_models.py b/minutes/tests/test_models.py
index fcd9bf571..4b5603641 100644
--- a/minutes/tests/test_models.py
+++ b/minutes/tests/test_models.py
@@ -21,16 +21,10 @@ def setUp(self):
         )
 
     def test_draft(self):
-        self.assertQuerysetEqual(
-            Minutes.objects.draft(),
-            ['<Minutes: PSF Meeting Minutes January 01, 2013>']
-        )
+        self.assertQuerySetEqual(Minutes.objects.draft(), ['<Minutes: PSF Meeting Minutes January 01, 2013>'], transform=repr)
 
     def test_published(self):
-        self.assertQuerysetEqual(
-            Minutes.objects.published(),
-            ['<Minutes: PSF Meeting Minutes January 01, 2012>']
-        )
+        self.assertQuerySetEqual(Minutes.objects.published(), ['<Minutes: PSF Meeting Minutes January 01, 2012>'], transform=repr)
 
     def test_date_methods(self):
         self.assertEqual(self.m1.get_date_year(), '2012')
diff --git a/nominations/__init__.py b/nominations/__init__.py
index 368a604a5..e69de29bb 100644
--- a/nominations/__init__.py
+++ b/nominations/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'nominations.apps.NominationsAppConfig'
diff --git a/pages/__init__.py b/pages/__init__.py
index 6f1e657eb..e69de29bb 100644
--- a/pages/__init__.py
+++ b/pages/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'pages.apps.PagesAppConfig'
diff --git a/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py b/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py
new file mode 100644
index 000000000..19c5a6082
--- /dev/null
+++ b/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('pages', '0003_auto_20230214_2113'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='page',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='page',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/pages/tests/test_api.py b/pages/tests/test_api.py
index 4026bac75..1c4cc6184 100644
--- a/pages/tests/test_api.py
+++ b/pages/tests/test_api.py
@@ -30,7 +30,7 @@ def test_get_published_pages(self):
     def test_get_all_pages(self):
         # Login to get all pages.
         url = self.create_url('page')
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(len(response.data), 3)
 
@@ -41,7 +41,7 @@ def test_filter_page(self):
         self.assertEqual(len(response.data), 1)
 
         # Login to filter all pages.
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(len(response.data), 2)
 
@@ -53,7 +53,7 @@ def test_filter_page(self):
         self.assertEqual(len(response.data), 0)
 
         # This should return only unpublished pages.
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.Authorization)
+        response = self.client.get(url, headers={"authorization": self.Authorization})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(len(response.data), 1)
 
diff --git a/pages/tests/test_models.py b/pages/tests/test_models.py
index 2215cc812..eac62f102 100644
--- a/pages/tests/test_models.py
+++ b/pages/tests/test_models.py
@@ -8,11 +8,11 @@
 
 
 class PageModelTests(BasePageTests):
-    def test_published(self):
-        self.assertQuerysetEqual(Page.objects.published(), ['<Page: One>'])
-
     def test_draft(self):
-        self.assertQuerysetEqual(Page.objects.draft(), ['<Page: Two>'])
+        self.assertQuerySetEqual(Page.objects.draft(), ['<Page: Two>'], transform=repr)
+
+    def test_published(self):
+        self.assertQuerySetEqual(Page.objects.published(), ['<Page: One>'], transform=repr)
 
     def test_get_title(self):
         one = Page.objects.get(path='one')
diff --git a/peps/__init__.py b/peps/__init__.py
index c71df1925..e69de29bb 100644
--- a/peps/__init__.py
+++ b/peps/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'peps.apps.PepsAppConfig'
diff --git a/prod-requirements.txt b/prod-requirements.txt
index a99aad083..a7c4022f1 100644
--- a/prod-requirements.txt
+++ b/prod-requirements.txt
@@ -3,6 +3,6 @@ gunicorn==22.0.0
 raven==6.10.0
 
 # Heroku
-Whitenoise==6.0.0  # 6.0.0 is latest version that supports Django 2.2
-django-storages==1.12.3  # 1.12.3 is latest version that supports Django 2.2
+Whitenoise==6.6.0  # 6.4.0 is first version that supports Django 4.2
+django-storages==1.42.2  # 1.42.2 is first version that supports Django 4.2
 boto3==1.26.165
diff --git a/pydotorg/settings/base.py b/pydotorg/settings/base.py
index a602dff7e..9697a6ea8 100644
--- a/pydotorg/settings/base.py
+++ b/pydotorg/settings/base.py
@@ -31,6 +31,12 @@
     )
 }
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+"""The default primary key field type for Django models.
+
+Required during the Django 2.2 -> 4.2 migration.
+"""
+
 # celery settings
 _REDIS_URL = config("REDIS_URL", default="redis://redis:6379/0")
 
@@ -53,7 +59,6 @@
 TIME_ZONE = 'UTC'
 LANGUAGE_CODE = 'en-us'
 USE_I18N = True
-USE_L10N = True
 USE_TZ = True
 
 DATE_FORMAT = 'Y-m-d'
@@ -74,7 +79,14 @@
 STATICFILES_DIRS = [
     os.path.join(BASE, 'static'),
 ]
-STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage'
+STORAGES = {
+    "default": {
+        "BACKEND": "django.core.files.storage.FileSystemStorage",
+    },
+    "staticfiles": {
+        "BACKEND": 'pipeline.storage.PipelineStorage',
+    },
+}
 STATICFILES_FINDERS = (
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
@@ -98,6 +110,8 @@
 ACCOUNT_UNIQUE_EMAIL = True
 ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
 ACCOUNT_AUTHENTICATION_METHOD = 'username_email'
+# TODO: Enable enumeration prevention
+ACCOUNT_PREVENT_ENUMERATION = False
 SOCIALACCOUNT_EMAIL_REQUIRED = True
 SOCIALACCOUNT_EMAIL_VERIFICATION = True
 SOCIALACCOUNT_QUERY_EMAIL = True
@@ -157,6 +171,7 @@
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'pages.middleware.PageFallbackMiddleware',
     'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
+    'allauth.account.middleware.AccountMiddleware',
 ]
 
 AUTH_USER_MODEL = 'users.User'
diff --git a/pydotorg/settings/cabotage.py b/pydotorg/settings/cabotage.py
index d73beb83c..4661fbf66 100644
--- a/pydotorg/settings/cabotage.py
+++ b/pydotorg/settings/cabotage.py
@@ -44,8 +44,14 @@
 ] + MIDDLEWARE
 
 MEDIAFILES_LOCATION = 'media'
-DEFAULT_FILE_STORAGE = 'custom_storages.storages.MediaStorage'
-STATICFILES_STORAGE = 'custom_storages.storages.PipelineManifestStorage'
+STORAGES = {
+    "default": {
+        "BACKEND": 'custom_storages.storages.MediaStorage',
+    },
+    "staticfiles": {
+        "BACKEND": 'custom_storages.storages.PipelineManifestStorage',
+    },
+}
 
 EMAIL_HOST = config('EMAIL_HOST')
 EMAIL_HOST_USER = config('EMAIL_HOST_USER')
diff --git a/pydotorg/settings/static.py b/pydotorg/settings/static.py
index 3d93e113e..5dcbf6f92 100644
--- a/pydotorg/settings/static.py
+++ b/pydotorg/settings/static.py
@@ -21,5 +21,11 @@
 ] + MIDDLEWARE
 
 MEDIAFILES_LOCATION = 'media'
-DEFAULT_FILE_STORAGE = 'custom_storages.storages.MediaStorage'
-STATICFILES_STORAGE = 'custom_storages.storages.PipelineManifestStorage'
+STORAGES = {
+    "default": {
+        "BACKEND": 'custom_storages.storages.MediaStorage',
+    },
+    "staticfiles": {
+        "BACKEND": 'custom_storages.storages.PipelineManifestStorage',
+    },
+}
diff --git a/pydotorg/urls.py b/pydotorg/urls.py
index f6ee8001d..f87ab496b 100644
--- a/pydotorg/urls.py
+++ b/pydotorg/urls.py
@@ -1,7 +1,8 @@
-from django.conf.urls import handler404, include
+from django.conf.urls import handler404
 from django.contrib import admin
 from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 from django.conf.urls.static import static
+from django.urls import include
 from django.urls import path, re_path
 from django.views.generic.base import TemplateView
 from django.conf import settings
diff --git a/pydotorg/urls_api.py b/pydotorg/urls_api.py
index 0c27699b1..4afc7122e 100644
--- a/pydotorg/urls_api.py
+++ b/pydotorg/urls_api.py
@@ -1,4 +1,4 @@
-from django.conf.urls import url
+from django.urls import re_path
 
 from rest_framework import routers
 from tastypie.api import Api
@@ -22,6 +22,6 @@
 router.register(r'downloads/release_file', ReleaseFileViewSet)
 
 urlpatterns = [
-    url(r'sponsors/logo-placement/', LogoPlacementeAPIList.as_view(), name="logo_placement_list"),
-    url(r'sponsors/sponsorship-assets/', SponsorshipAssetsAPIList.as_view(), name="assets_list"),
+    re_path(r'sponsors/logo-placement/', LogoPlacementeAPIList.as_view(), name="logo_placement_list"),
+    re_path(r'sponsors/sponsorship-assets/', SponsorshipAssetsAPIList.as_view(), name="assets_list"),
 ]
diff --git a/sponsors/__init__.py b/sponsors/__init__.py
index 016e79088..e69de29bb 100644
--- a/sponsors/__init__.py
+++ b/sponsors/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'sponsors.apps.SponsorsAppConfig'
diff --git a/sponsors/admin.py b/sponsors/admin.py
index e16cffbc6..dc7278c08 100644
--- a/sponsors/admin.py
+++ b/sponsors/admin.py
@@ -38,18 +38,22 @@ class AssetsInline(GenericTabularInline):
     has_delete_permission = lambda self, request, obj: False
     readonly_fields = ["internal_name", "user_submitted_info", "value"]
 
+    @admin.display(
+        description="Submitted information"
+    )
     def value(self, obj=None):
         if not obj or not obj.value:
             return ""
         return obj.value
 
-    value.short_description = "Submitted information"
 
+    @admin.display(
+        description="Fullfilled data?",
+        boolean=True,
+    )
     def user_submitted_info(self, obj=None):
         return bool(self.value(obj))
 
-    user_submitted_info.short_description = "Fullfilled data?"
-    user_submitted_info.boolean = True
 
 
 @admin.register(SponsorshipProgram)
@@ -235,10 +239,12 @@ class SponsorshipsInline(admin.TabularInline):
     can_delete = False
     extra = 0
 
+    @admin.display(
+        description="ID"
+    )
     def link(self, obj):
         url = reverse("admin:sponsors_sponsorship_change", args=[obj.id])
         return mark_safe(f"<a href={url}>{obj.id}</a>")
-    link.short_description = "ID"
 
 
 @admin.register(Sponsor)
@@ -489,10 +495,12 @@ def get_queryset(self, *args, **kwargs):
         qs = super().get_queryset(*args, **kwargs)
         return qs.select_related("sponsor", "package", "submited_by")
 
+    @admin.action(
+        description='Send notifications to selected'
+    )
     def send_notifications(self, request, queryset):
         return views_admin.send_sponsorship_notifications_action(self, request, queryset)
 
-    send_notifications.short_description = 'Send notifications to selected'
 
     def get_readonly_fields(self, request, obj):
         readonly_fields = [
@@ -528,11 +536,16 @@ def get_readonly_fields(self, request, obj):
 
         return readonly_fields
 
+    @admin.display(
+        description="Sponsor"
+    )
     def sponsor_link(self, obj):
         url = reverse("admin:sponsors_sponsor_change", args=[obj.sponsor.id])
         return mark_safe(f"<a href={url}>{obj.sponsor.name}</a>")
-    sponsor_link.short_description = "Sponsor"
 
+    @admin.display(
+        description="Estimated cost"
+    )
     def get_estimated_cost(self, obj):
         cost = None
         html = "This sponsorship has not customizations so there's no estimated cost"
@@ -542,8 +555,10 @@ def get_estimated_cost(self, obj):
             html = f"{cost} USD <br/><b>Important: </b> {msg}"
         return mark_safe(html)
 
-    get_estimated_cost.short_description = "Estimated cost"
 
+    @admin.display(
+        description="Contract"
+    )
     def get_contract(self, obj):
         if not obj.contract:
             return "---"
@@ -551,7 +566,6 @@ def get_contract(self, obj):
         html = f"<a href='{url}' target='_blank'>{obj.contract}</a>"
         return mark_safe(html)
 
-    get_contract.short_description = "Contract"
 
     def get_urls(self):
         urls = super().get_urls()
@@ -597,21 +611,30 @@ def get_urls(self):
         ]
         return my_urls + urls
 
+    @admin.display(
+        description="Name"
+    )
     def get_sponsor_name(self, obj):
         return obj.sponsor.name
 
-    get_sponsor_name.short_description = "Name"
 
+    @admin.display(
+        description="Description"
+    )
     def get_sponsor_description(self, obj):
         return obj.sponsor.description
 
-    get_sponsor_description.short_description = "Description"
 
+    @admin.display(
+        description="Landing Page URL"
+    )
     def get_sponsor_landing_page_url(self, obj):
         return obj.sponsor.landing_page_url
 
-    get_sponsor_landing_page_url.short_description = "Landing Page URL"
 
+    @admin.display(
+        description="Web Logo"
+    )
     def get_sponsor_web_logo(self, obj):
         html = "{% load thumbnail %}{% thumbnail sponsor.web_logo '150x150' format='PNG' quality=100 as im %}<img src='{{ im.url}}'/>{% endthumbnail %}"
         template = Template(html)
@@ -619,8 +642,10 @@ def get_sponsor_web_logo(self, obj):
         html = template.render(context)
         return mark_safe(html)
 
-    get_sponsor_web_logo.short_description = "Web Logo"
 
+    @admin.display(
+        description="Print Logo"
+    )
     def get_sponsor_print_logo(self, obj):
         img = obj.sponsor.print_logo
         html = ""
@@ -631,13 +656,17 @@ def get_sponsor_print_logo(self, obj):
             html = template.render(context)
         return mark_safe(html) if html else "---"
 
-    get_sponsor_print_logo.short_description = "Print Logo"
 
+    @admin.display(
+        description="Primary Phone"
+    )
     def get_sponsor_primary_phone(self, obj):
         return obj.sponsor.primary_phone
 
-    get_sponsor_primary_phone.short_description = "Primary Phone"
 
+    @admin.display(
+        description="Mailing/Billing Address"
+    )
     def get_sponsor_mailing_address(self, obj):
         sponsor = obj.sponsor
         city_row = (
@@ -655,8 +684,10 @@ def get_sponsor_mailing_address(self, obj):
         html += f"<p>{sponsor.postal_code}</p>"
         return mark_safe(html)
 
-    get_sponsor_mailing_address.short_description = "Mailing/Billing Address"
 
+    @admin.display(
+        description="Contacts"
+    )
     def get_sponsor_contacts(self, obj):
         html = ""
         contacts = obj.sponsor.contacts.all()
@@ -676,8 +707,10 @@ def get_sponsor_contacts(self, obj):
             html += "</ul>"
         return mark_safe(html)
 
-    get_sponsor_contacts.short_description = "Contacts"
 
+    @admin.display(
+        description="Added by User"
+    )
     def get_custom_benefits_added_by_user(self, obj):
         benefits = obj.user_customizations["added_by_user"]
         if not benefits:
@@ -688,8 +721,10 @@ def get_custom_benefits_added_by_user(self, obj):
         )
         return mark_safe(html)
 
-    get_custom_benefits_added_by_user.short_description = "Added by User"
 
+    @admin.display(
+        description="Removed by User"
+    )
     def get_custom_benefits_removed_by_user(self, obj):
         benefits = obj.user_customizations["removed_by_user"]
         if not benefits:
@@ -700,7 +735,6 @@ def get_custom_benefits_removed_by_user(self, obj):
         )
         return mark_safe(html)
 
-    get_custom_benefits_removed_by_user.short_description = "Removed by User"
 
     def rollback_to_editing_view(self, request, pk):
         return views_admin.rollback_to_editing_view(self, request, pk)
@@ -747,6 +781,9 @@ def get_urls(self):
         ]
         return my_urls + urls
 
+    @admin.display(
+        description="Links"
+    )
     def links(self, obj):
         clone_form = CloneApplicationConfigForm()
         configured_years = clone_form.configured_years
@@ -768,8 +805,10 @@ def links(self, obj):
         html += f"<li><a target='_blank' href='{preview_url}'>{preview_label}</a>"
         html += "</ul>"
         return mark_safe(html)
-    links.short_description = "Links"
 
+    @admin.display(
+        description="Other configured years"
+    )
     def other_years(self, obj):
         clone_form = CloneApplicationConfigForm()
         configured_years = clone_form.configured_years
@@ -800,7 +839,6 @@ def other_years(self, obj):
             html += "</ul></li>"
         html += "</ul>"
         return mark_safe(html)
-    other_years.short_description = "Other configured years"
 
     def clone_application_config(self, request):
         return views_admin.clone_application_config(self, request)
@@ -828,10 +866,12 @@ def get_queryset(self, *args, **kwargs):
         qs = super().get_queryset(*args, **kwargs)
         return qs.select_related("sponsorship__sponsor")
 
+    @admin.display(
+        description="Revision"
+    )
     def get_revision(self, obj):
         return obj.revision if obj.is_draft else "Final"
 
-    get_revision.short_description = "Revision"
 
     fieldsets = [
         (
@@ -899,6 +939,9 @@ def get_readonly_fields(self, request, obj):
 
         return readonly_fields
 
+    @admin.display(
+        description="Contract document"
+    )
     def document_link(self, obj):
         html, url, msg = "---", "", ""
 
@@ -916,8 +959,10 @@ def document_link(self, obj):
             html = f'<a href="{url}" target="_blank">{msg}</a>'
         return mark_safe(html)
 
-    document_link.short_description = "Contract document"
 
+    @admin.display(
+        description="Sponsorship"
+    )
     def get_sponsorship_url(self, obj):
         if not obj.sponsorship:
             return "---"
@@ -925,7 +970,6 @@ def get_sponsorship_url(self, obj):
         html = f"<a href='{url}' target='_blank'>{obj.sponsorship}</a>"
         return mark_safe(html)
 
-    get_sponsorship_url.short_description = "Sponsorship"
 
     def get_urls(self):
         urls = super().get_urls()
@@ -1090,14 +1134,19 @@ def all_sponsorships(self):
         qs = Sponsorship.objects.all().select_related("package", "sponsor")
         return {sp.id: sp for sp in qs}
 
+    @admin.display(
+        description="Value"
+    )
     def get_value(self, obj):
         html = obj.value
         if obj.value and getattr(obj.value, "url", None):
             html = f"<a href='{obj.value.url}' target='_blank'>{obj.value}</a>"
         return mark_safe(html)
 
-    get_value.short_description = "Value"
 
+    @admin.display(
+        description="Associated with"
+    )
     def get_related_object(self, obj):
         """
         Returns the content_object as an URL and performs better because
@@ -1115,11 +1164,12 @@ def get_related_object(self, obj):
         html = f"<a href='{content_object.admin_url}' target='_blank'>{content_object}</a>"
         return mark_safe(html)
 
-    get_related_object.short_description = "Associated with"
 
+    @admin.action(
+        description="Export selected"
+    )
     def export_assets_as_zipfile(self, request, queryset):
         return views_admin.export_assets_as_zipfile(self, request, queryset)
-    export_assets_as_zipfile.short_description = "Export selected"
 
 
 class GenericAssetChildModelAdmin(PolymorphicChildModelAdmin):
diff --git a/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py b/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py
new file mode 100644
index 000000000..e9eb9e3a2
--- /dev/null
+++ b/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py
@@ -0,0 +1,47 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('sponsors', '0102_auto_20240509_2037'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='benefitfeature',
+            name='polymorphic_ctype',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'),
+        ),
+        migrations.AlterField(
+            model_name='benefitfeatureconfiguration',
+            name='polymorphic_ctype',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'),
+        ),
+        migrations.AlterField(
+            model_name='genericasset',
+            name='polymorphic_ctype',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype'),
+        ),
+        migrations.AlterField(
+            model_name='sponsor',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='sponsor',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='sponsorshipbenefit',
+            name='conflicts',
+            field=models.ManyToManyField(blank=True, help_text='For benefits that conflict with one another,', to='sponsors.sponsorshipbenefit', verbose_name='Conflicts'),
+        ),
+    ]
diff --git a/sponsors/tests/test_api.py b/sponsors/tests/test_api.py
index caabd6aa1..3575e59e6 100644
--- a/sponsors/tests/test_api.py
+++ b/sponsors/tests/test_api.py
@@ -41,7 +41,7 @@ def tearDown(self):
                 sponsor.print_logo.delete()
 
     def test_list_logo_placement_as_expected(self):
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(200, response.status_code)
@@ -71,7 +71,7 @@ def test_list_logo_placement_as_expected(self):
 
     def test_invalid_token(self):
         Token.objects.all().delete()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(401, response.status_code)
 
     def test_superuser_user_have_permission_by_default(self):
@@ -79,19 +79,19 @@ def test_superuser_user_have_permission_by_default(self):
         self.user.is_superuser = True
         self.user.is_staff = True
         self.user.save()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(200, response.status_code)
 
     def test_staff_have_permission_by_default(self):
         self.user.user_permissions.remove(self.permission)
         self.user.is_staff = True
         self.user.save()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(200, response.status_code)
 
     def test_user_must_have_required_permission(self):
         self.user.user_permissions.remove(self.permission)
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(403, response.status_code)
 
     def test_filter_sponsorship_by_publisher(self):
@@ -99,7 +99,7 @@ def test_filter_sponsorship_by_publisher(self):
             "publisher": PublisherChoices.PYPI.value,
         })
         url = f"{self.url}?{querystring}"
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(200, response.status_code)
@@ -111,7 +111,7 @@ def test_filter_sponsorship_by_flight(self):
             "flight": LogoPlacementChoices.SIDEBAR.value,
         })
         url = f"{self.url}?{querystring}"
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(200, response.status_code)
@@ -125,7 +125,7 @@ def test_bad_request_for_invalid_filters(self):
             "publisher": "invalid-publisher"
         })
         url = f"{self.url}?{querystring}"
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(400, response.status_code)
@@ -162,7 +162,7 @@ def tearDown(self):
 
     def test_invalid_token(self):
         Token.objects.all().delete()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(401, response.status_code)
 
     def test_superuser_user_have_permission_by_default(self):
@@ -170,30 +170,30 @@ def test_superuser_user_have_permission_by_default(self):
         self.user.is_superuser = True
         self.user.is_staff = True
         self.user.save()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(200, response.status_code)
 
     def test_staff_have_permission_by_default(self):
         self.user.user_permissions.remove(self.permission)
         self.user.is_staff = True
         self.user.save()
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(200, response.status_code)
 
     def test_user_must_have_required_permission(self):
         self.user.user_permissions.remove(self.permission)
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         self.assertEqual(403, response.status_code)
 
     def test_bad_request_if_no_internal_name(self):
         url = reverse_lazy("assets_list")
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(url, headers={"authorization": self.authorization})
         self.assertEqual(400, response.status_code)
         self.assertIn("internal_name", response.json())
 
     def test_list_assets_by_internal_name(self):
         # by default exclude assets with no value
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         data = response.json()
         self.assertEqual(200, response.status_code)
         self.assertEqual(0, len(data))
@@ -202,7 +202,7 @@ def test_list_assets_by_internal_name(self):
         self.txt_asset.value = "Text Content"
         self.txt_asset.save()
 
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(1, len(data))
@@ -216,7 +216,7 @@ def test_list_assets_by_internal_name(self):
     def test_enable_to_filter_by_assets_with_no_value_via_querystring(self):
         self.url += "&list_empty=true"
 
-        response = self.client.get(self.url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(self.url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(1, len(data))
@@ -230,7 +230,7 @@ def test_serialize_img_value_as_url_to_image(self):
         self.img_asset.save()
 
         url = reverse_lazy("assets_list") + f"?internal_name={self.img_asset.internal_name}"
-        response = self.client.get(url, HTTP_AUTHORIZATION=self.authorization)
+        response = self.client.get(url, headers={"authorization": self.authorization})
         data = response.json()
 
         self.assertEqual(1, len(data))
diff --git a/successstories/__init__.py b/successstories/__init__.py
index e2c2c1446..e69de29bb 100644
--- a/successstories/__init__.py
+++ b/successstories/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'successstories.apps.SuccessstoriesAppConfig'
diff --git a/successstories/admin.py b/successstories/admin.py
index fdde8878c..bc15d2d11 100644
--- a/successstories/admin.py
+++ b/successstories/admin.py
@@ -24,6 +24,8 @@ def get_list_display(self, request):
         fields = list(super().get_list_display(request))
         return fields + ['show_link', 'is_published', 'featured']
 
+    @admin.display(
+        description='View on site'
+    )
     def show_link(self, obj):
         return format_html(f'<a href="{obj.get_absolute_url()}">\U0001F517</a>')
-    show_link.short_description = 'View on site'
diff --git a/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py b/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py
new file mode 100644
index 000000000..dee246421
--- /dev/null
+++ b/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('successstories', '0011_auto_20220127_1923'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='story',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='story',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/successstories/tests/test_models.py b/successstories/tests/test_models.py
index de5c0d577..418d27062 100644
--- a/successstories/tests/test_models.py
+++ b/successstories/tests/test_models.py
@@ -15,12 +15,13 @@ def test_published(self):
         self.assertEqual(len(Story.objects.published()), 2)
 
     def test_draft(self):
-        self.assertQuerysetEqual(Story.objects.draft(),
-                                 [f'<Story: {self.story2.name}>'])
+        draft_stories = Story.objects.draft()
+        self.assertTrue(all(story.name == 'Fraft Story' for story in draft_stories))
 
     def test_featured(self):
-        self.assertQuerysetEqual(Story.objects.featured(),
-                                 [f'<Story: {self.story3.name}>'])
+        featured_stories = Story.objects.featured()
+        expected_repr = [f'<Story: {self.story3.name}>']
+        self.assertQuerysetEqual(featured_stories, expected_repr, transform=repr)
 
     def test_get_admin_url(self):
         self.assertEqual(self.story1.get_admin_url(),
diff --git a/users/__init__.py b/users/__init__.py
index 1bf67ae9c..e69de29bb 100644
--- a/users/__init__.py
+++ b/users/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'users.apps.UsersAppConfig'
diff --git a/users/admin.py b/users/admin.py
index 1c003655c..36d7e30f3 100644
--- a/users/admin.py
+++ b/users/admin.py
@@ -26,7 +26,7 @@ class ApiKeyInline(TastypieApiKeyInline):
 
 @admin.register(User)
 class UserAdmin(BaseUserAdmin):
-    inlines = BaseUserAdmin.inlines + [ApiKeyInline, MembershipInline]
+    inlines = BaseUserAdmin.inlines + (ApiKeyInline, MembershipInline,)
     fieldsets = (
         (None, {'fields': ('username', 'password')}),
         (_('Personal info'), {'fields': (
@@ -44,9 +44,11 @@ class UserAdmin(BaseUserAdmin):
     def has_add_permission(self, request):
         return False
 
+    @admin.display(
+        description='Name'
+    )
     def full_name(self, obj):
         return obj.get_full_name()
-    full_name.short_description = 'Name'
 
 
 @admin.register(Membership)
diff --git a/users/migrations/0015_alter_user_first_name.py b/users/migrations/0015_alter_user_first_name.py
new file mode 100644
index 000000000..ac7715204
--- /dev/null
+++ b/users/migrations/0015_alter_user_first_name.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('users', '0014_auto_20210801_2332'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='user',
+            name='first_name',
+            field=models.CharField(blank=True, max_length=150, verbose_name='first name'),
+        ),
+    ]
diff --git a/users/tests/test_forms.py b/users/tests/test_forms.py
index 10ab95e32..897f41d6c 100644
--- a/users/tests/test_forms.py
+++ b/users/tests/test_forms.py
@@ -2,6 +2,7 @@
 from django.test import TestCase
 
 from allauth.account.forms import SignupForm
+from allauth.account.models import EmailAddress
 
 from users.forms import UserProfileForm, MembershipForm
 
@@ -50,14 +51,16 @@ def test_duplicate_username(self):
         self.assertIn('username', form.errors)
 
     def test_duplicate_email(self):
-        User.objects.create_user('test1', 'test@example.com', 'testpass')
+        user = User.objects.create_user('test1', 'test@example.com', 'testpass')
+        EmailAddress.objects.create(user=user, email="test@example.com")
 
-        form = SignupForm({
+        form = SignupForm(data={
             'username': 'username2',
             'email': 'test@example.com',
             'password1': 'password',
-            'password2': 'password'
+            'password2': 'password',
         })
+
         self.assertFalse(form.is_valid())
         self.assertIn('email', form.errors)
 
@@ -92,13 +95,8 @@ def test_non_ascii_username(self):
             'password2': 'password',
         })
         self.assertFalse(form.is_valid())
-        self.assertEqual(
-            form.errors['username'],
-            [
-                'Enter a valid username. This value may contain only '
-                'English letters, numbers, and @/./+/-/_ characters.'
-            ]
-        )
+        expected_error = 'Enter a valid username. This value may contain only unaccented lowercase a-z and uppercase A-Z letters, numbers, and @/./+/-/_ characters.'
+        self.assertIn(expected_error, form.errors['username'])
 
     def test_user_membership(self):
         form = MembershipForm({
diff --git a/users/tests/test_views.py b/users/tests/test_views.py
index 13c226e5f..83b8330f9 100644
--- a/users/tests/test_views.py
+++ b/users/tests/test_views.py
@@ -2,7 +2,7 @@
 from django.conf import settings
 from django.contrib.auth import get_user_model
 from django.urls import reverse
-from django.test import TestCase
+from django.test import TestCase, override_settings
 
 from sponsors.forms import SponsorUpdateForm, SponsorRequiredAssetsForm
 from sponsors.models import Sponsorship, RequiredTextAssetConfiguration, SponsorBenefit
@@ -11,8 +11,6 @@
 from users.factories import UserFactory
 from users.models import Membership
 
-from ..factories import MembershipFactory
-
 User = get_user_model()
 
 
@@ -245,7 +243,7 @@ def test_user_duplicate_username_email(self):
             response, 'A user with that username already exists.'
         )
         self.assertContains(
-            response, 'A user is already registered with this e-mail address.'
+            response, 'A user is already registered with this email address.'
         )
 
     def test_usernames(self):
diff --git a/work_groups/__init__.py b/work_groups/__init__.py
index ef2fbcce9..e69de29bb 100644
--- a/work_groups/__init__.py
+++ b/work_groups/__init__.py
@@ -1 +0,0 @@
-default_app_config = 'work_groups.apps.WorkGroupsAppConfig'
diff --git a/work_groups/migrations/0005_alter_workgroup_creator_and_more.py b/work_groups/migrations/0005_alter_workgroup_creator_and_more.py
new file mode 100644
index 000000000..a316aa482
--- /dev/null
+++ b/work_groups/migrations/0005_alter_workgroup_creator_and_more.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.11 on 2024-09-05 17:10
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('work_groups', '0004_auto_20180705_0352'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='workgroup',
+            name='creator',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_creator', to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='workgroup',
+            name='last_modified_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_modified', to=settings.AUTH_USER_MODEL),
+        ),
+    ]