We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`get_follow_object_pk` errors out if `obj.follow_object` is `None`
Occurs when the follow object has been deleted and the follow is not cleaned up. See https://sentry.io/organizations/grand-challenge/issues/2511041483/?project=303639&query=is%3Aunresolved

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/grandchallenge/notifications/signals.py`
Content:
```
1 from actstream import action
2 from actstream.actions import follow
3 from actstream.models import Action, Follow, followers
4 from django.db.models.signals import post_save
5 from django.dispatch import receiver
6 from guardian.shortcuts import assign_perm
7 from machina.apps.forum_conversation.models import Post, Topic
8 
9 from grandchallenge.notifications.models import Notification
10 
11 
12 @receiver(post_save, sender=Topic)
13 def create_topic_action(sender, *, instance, created, **_):
14     if created:
15         follow(
16             user=instance.poster,
17             obj=instance,
18             actor_only=False,
19             send_action=False,
20         )
21 
22         if int(instance.type) == int(Topic.TOPIC_ANNOUNCE):
23             action.send(
24                 sender=instance.poster,
25                 verb="announced",
26                 action_object=instance,
27                 target=instance.forum,
28                 context_class="info",
29             )
30         else:
31             action.send(
32                 sender=instance.poster,
33                 verb="posted",
34                 action_object=instance,
35                 target=instance.forum,
36             )
37 
38 
39 @receiver(post_save, sender=Post)
40 def create_post_action(sender, *, instance, created, **_):
41     if (
42         created
43         and instance.topic.posts_count != 0
44         and not instance.is_topic_head
45     ):
46         follow(
47             user=instance.poster,
48             obj=instance.topic,
49             actor_only=False,
50             send_action=False,
51         )
52 
53         action.send(
54             sender=instance.poster, verb="replied to", target=instance.topic,
55         )
56 
57 
58 @receiver(post_save, sender=Action)
59 def create_notification(*, instance, **_):
60     if instance.target:
61         follower_group = followers(instance.target)
62         for follower in follower_group:
63             # only send notifications to followers other than the poster
64             if follower != instance.actor:
65                 Notification(user=follower, action=instance).save()
66     else:
67         follower_group = followers(instance.actor)
68         for follower in follower_group:
69             # only send notifications to followers other than the poster
70             if follower != instance.actor:
71                 Notification(user=follower, action=instance).save()
72 
73 
74 @receiver(post_save, sender=Follow)
75 def add_permissions(*, instance, created, **_):
76     if created:
77         assign_perm("change_follow", instance.user, instance)
78         assign_perm("delete_follow", instance.user, instance)
79         assign_perm("view_follow", instance.user, instance)
80
```

Path: `app/grandchallenge/forum_conversation/templatetags/forum_extras.py`
Content:
```
1 from actstream.models import Follow
2 from django import template
3 from django.contrib.contenttypes.models import ContentType
4 
5 from grandchallenge.notifications.forms import FollowForm
6 
7 register = template.Library()
8 
9 
10 @register.simple_tag
11 def get_follow_object_pk(user, follow_object):
12     object_follows_for_user = Follow.objects.filter(
13         user=user,
14         content_type=ContentType.objects.get(
15             app_label=follow_object._meta.app_label,
16             model=follow_object._meta.model_name,
17         ),
18     ).all()
19     current_follow_object = []
20     for obj in object_follows_for_user:
21         if obj.follow_object.id == follow_object.id:
22             current_follow_object = obj.pk
23     return current_follow_object
24 
25 
26 @register.simple_tag
27 def follow_form(*, user, object_id, content_type):
28     return FollowForm(
29         user=user,
30         initial={
31             "object_id": object_id,
32             "content_type": content_type,
33             "actor_only": False,
34         },
35     )
36 
37 
38 @register.simple_tag()
39 def get_content_type(follow_object):
40     ct = ContentType.objects.get(
41         app_label=follow_object._meta.app_label,
42         model=follow_object._meta.model_name,
43     )
44     return ct
45
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
--- a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
+++ b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py
@@ -16,10 +16,16 @@
             model=follow_object._meta.model_name,
         ),
     ).all()
-    current_follow_object = []
-    for obj in object_follows_for_user:
-        if obj.follow_object.id == follow_object.id:
-            current_follow_object = obj.pk
+
+    if not object_follows_for_user:
+        current_follow_object = []
+    else:
+        current_follow_object = []
+        for obj in object_follows_for_user:
+            if not obj.follow_object:
+                continue
+            elif obj.follow_object.id == follow_object.id:
+                current_follow_object = obj.pk
     return current_follow_object
 
 
@@ -37,8 +43,11 @@
 
 @register.simple_tag()
 def get_content_type(follow_object):
-    ct = ContentType.objects.get(
-        app_label=follow_object._meta.app_label,
-        model=follow_object._meta.model_name,
-    )
+    try:
+        ct = ContentType.objects.get(
+            app_label=follow_object._meta.app_label,
+            model=follow_object._meta.model_name,
+        )
+    except AttributeError:
+        ct = None
     return ct
diff --git a/app/grandchallenge/notifications/signals.py b/app/grandchallenge/notifications/signals.py
--- a/app/grandchallenge/notifications/signals.py
+++ b/app/grandchallenge/notifications/signals.py
@@ -1,9 +1,11 @@
 from actstream import action
 from actstream.actions import follow
 from actstream.models import Action, Follow, followers
-from django.db.models.signals import post_save
+from django.contrib.contenttypes.models import ContentType
+from django.db.models.signals import post_save, pre_delete
 from django.dispatch import receiver
 from guardian.shortcuts import assign_perm
+from machina.apps.forum.models import Forum
 from machina.apps.forum_conversation.models import Post, Topic
 
 from grandchallenge.notifications.models import Notification
@@ -77,3 +79,13 @@
         assign_perm("change_follow", instance.user, instance)
         assign_perm("delete_follow", instance.user, instance)
         assign_perm("view_follow", instance.user, instance)
+
+
+@receiver(pre_delete, sender=Topic)
+@receiver(pre_delete, sender=Forum)
+@receiver(pre_delete, sender=Post)
+def clean_up_follows(*, instance, **_):
+    ct = ContentType.objects.filter(
+        app_label=instance._meta.app_label, model=instance._meta.model_name
+    ).get()
+    Follow.objects.filter(content_type=ct, object_id=instance.pk).delete()

{"golden_diff": "diff --git a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py\n--- a/app/grandchallenge/forum_conversation/templatetags/forum_extras.py\n+++ b/app/grandchallenge/forum_conversation/templatetags/forum_extras.py\n@@ -16,10 +16,16 @@\n             model=follow_object._meta.model_name,\r\n         ),\r\n     ).all()\r\n-    current_follow_object = []\r\n-    for obj in object_follows_for_user:\r\n-        if obj.follow_object.id == follow_object.id:\r\n-            current_follow_object = obj.pk\r\n+\r\n+    if not object_follows_for_user:\r\n+        current_follow_object = []\r\n+    else:\r\n+        current_follow_object = []\r\n+        for obj in object_follows_for_user:\r\n+            if not obj.follow_object:\r\n+                continue\r\n+            elif obj.follow_object.id == follow_object.id:\r\n+                current_follow_object = obj.pk\r\n     return current_follow_object\r\n \r\n \r\n@@ -37,8 +43,11 @@\n \r\n @register.simple_tag()\r\n def get_content_type(follow_object):\r\n-    ct = ContentType.objects.get(\r\n-        app_label=follow_object._meta.app_label,\r\n-        model=follow_object._meta.model_name,\r\n-    )\r\n+    try:\r\n+        ct = ContentType.objects.get(\r\n+            app_label=follow_object._meta.app_label,\r\n+            model=follow_object._meta.model_name,\r\n+        )\r\n+    except AttributeError:\r\n+        ct = None\r\n     return ct\r\ndiff --git a/app/grandchallenge/notifications/signals.py b/app/grandchallenge/notifications/signals.py\n--- a/app/grandchallenge/notifications/signals.py\n+++ b/app/grandchallenge/notifications/signals.py\n@@ -1,9 +1,11 @@\n from actstream import action\n from actstream.actions import follow\n from actstream.models import Action, Follow, followers\n-from django.db.models.signals import post_save\n+from django.contrib.contenttypes.models import ContentType\n+from django.db.models.signals import post_save, pre_delete\n from django.dispatch import receiver\n from guardian.shortcuts import assign_perm\n+from machina.apps.forum.models import Forum\n from machina.apps.forum_conversation.models import Post, Topic\n \n from grandchallenge.notifications.models import Notification\n@@ -77,3 +79,13 @@\n         assign_perm(\"change_follow\", instance.user, instance)\n         assign_perm(\"delete_follow\", instance.user, instance)\n         assign_perm(\"view_follow\", instance.user, instance)\n+\n+\n+@receiver(pre_delete, sender=Topic)\n+@receiver(pre_delete, sender=Forum)\n+@receiver(pre_delete, sender=Post)\n+def clean_up_follows(*, instance, **_):\n+    ct = ContentType.objects.filter(\n+        app_label=instance._meta.app_label, model=instance._meta.model_name\n+    ).get()\n+    Follow.objects.filter(content_type=ct, object_id=instance.pk).delete()\n", "issue": "`get_follow_object_pk` errors out if `obj.follow_object` is `None`\nOccurs when the follow object has been deleted and the follow is not cleaned up. See https://sentry.io/organizations/grand-challenge/issues/2511041483/?project=303639&query=is%3Aunresolved\n", "before_files": [{"content": "from actstream import action\nfrom actstream.actions import follow\nfrom actstream.models import Action, Follow, followers\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom guardian.shortcuts import assign_perm\nfrom machina.apps.forum_conversation.models import Post, Topic\n\nfrom grandchallenge.notifications.models import Notification\n\n\n@receiver(post_save, sender=Topic)\ndef create_topic_action(sender, *, instance, created, **_):\n    if created:\n        follow(\n            user=instance.poster,\n            obj=instance,\n            actor_only=False,\n            send_action=False,\n        )\n\n        if int(instance.type) == int(Topic.TOPIC_ANNOUNCE):\n            action.send(\n                sender=instance.poster,\n                verb=\"announced\",\n                action_object=instance,\n                target=instance.forum,\n                context_class=\"info\",\n            )\n        else:\n            action.send(\n                sender=instance.poster,\n                verb=\"posted\",\n                action_object=instance,\n                target=instance.forum,\n            )\n\n\n@receiver(post_save, sender=Post)\ndef create_post_action(sender, *, instance, created, **_):\n    if (\n        created\n        and instance.topic.posts_count != 0\n        and not instance.is_topic_head\n    ):\n        follow(\n            user=instance.poster,\n            obj=instance.topic,\n            actor_only=False,\n            send_action=False,\n        )\n\n        action.send(\n            sender=instance.poster, verb=\"replied to\", target=instance.topic,\n        )\n\n\n@receiver(post_save, sender=Action)\ndef create_notification(*, instance, **_):\n    if instance.target:\n        follower_group = followers(instance.target)\n        for follower in follower_group:\n            # only send notifications to followers other than the poster\n            if follower != instance.actor:\n                Notification(user=follower, action=instance).save()\n    else:\n        follower_group = followers(instance.actor)\n        for follower in follower_group:\n            # only send notifications to followers other than the poster\n            if follower != instance.actor:\n                Notification(user=follower, action=instance).save()\n\n\n@receiver(post_save, sender=Follow)\ndef add_permissions(*, instance, created, **_):\n    if created:\n        assign_perm(\"change_follow\", instance.user, instance)\n        assign_perm(\"delete_follow\", instance.user, instance)\n        assign_perm(\"view_follow\", instance.user, instance)\n", "path": "app/grandchallenge/notifications/signals.py"}, {"content": "from actstream.models import Follow\r\nfrom django import template\r\nfrom django.contrib.contenttypes.models import ContentType\r\n\r\nfrom grandchallenge.notifications.forms import FollowForm\r\n\r\nregister = template.Library()\r\n\r\n\r\n@register.simple_tag\r\ndef get_follow_object_pk(user, follow_object):\r\n    object_follows_for_user = Follow.objects.filter(\r\n        user=user,\r\n        content_type=ContentType.objects.get(\r\n            app_label=follow_object._meta.app_label,\r\n            model=follow_object._meta.model_name,\r\n        ),\r\n    ).all()\r\n    current_follow_object = []\r\n    for obj in object_follows_for_user:\r\n        if obj.follow_object.id == follow_object.id:\r\n            current_follow_object = obj.pk\r\n    return current_follow_object\r\n\r\n\r\n@register.simple_tag\r\ndef follow_form(*, user, object_id, content_type):\r\n    return FollowForm(\r\n        user=user,\r\n        initial={\r\n            \"object_id\": object_id,\r\n            \"content_type\": content_type,\r\n            \"actor_only\": False,\r\n        },\r\n    )\r\n\r\n\r\n@register.simple_tag()\r\ndef get_content_type(follow_object):\r\n    ct = ContentType.objects.get(\r\n        app_label=follow_object._meta.app_label,\r\n        model=follow_object._meta.model_name,\r\n    )\r\n    return ct\r\n", "path": "app/grandchallenge/forum_conversation/templatetags/forum_extras.py"}], "after_files": [{"content": "from actstream import action\nfrom actstream.actions import follow\nfrom actstream.models import Action, Follow, followers\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.db.models.signals import post_save, pre_delete\nfrom django.dispatch import receiver\nfrom guardian.shortcuts import assign_perm\nfrom machina.apps.forum.models import Forum\nfrom machina.apps.forum_conversation.models import Post, Topic\n\nfrom grandchallenge.notifications.models import Notification\n\n\n@receiver(post_save, sender=Topic)\ndef create_topic_action(sender, *, instance, created, **_):\n    if created:\n        follow(\n            user=instance.poster,\n            obj=instance,\n            actor_only=False,\n            send_action=False,\n        )\n\n        if int(instance.type) == int(Topic.TOPIC_ANNOUNCE):\n            action.send(\n                sender=instance.poster,\n                verb=\"announced\",\n                action_object=instance,\n                target=instance.forum,\n                context_class=\"info\",\n            )\n        else:\n            action.send(\n                sender=instance.poster,\n                verb=\"posted\",\n                action_object=instance,\n                target=instance.forum,\n            )\n\n\n@receiver(post_save, sender=Post)\ndef create_post_action(sender, *, instance, created, **_):\n    if (\n        created\n        and instance.topic.posts_count != 0\n        and not instance.is_topic_head\n    ):\n        follow(\n            user=instance.poster,\n            obj=instance.topic,\n            actor_only=False,\n            send_action=False,\n        )\n\n        action.send(\n            sender=instance.poster, verb=\"replied to\", target=instance.topic,\n        )\n\n\n@receiver(post_save, sender=Action)\ndef create_notification(*, instance, **_):\n    if instance.target:\n        follower_group = followers(instance.target)\n        for follower in follower_group:\n            # only send notifications to followers other than the poster\n            if follower != instance.actor:\n                Notification(user=follower, action=instance).save()\n    else:\n        follower_group = followers(instance.actor)\n        for follower in follower_group:\n            # only send notifications to followers other than the poster\n            if follower != instance.actor:\n                Notification(user=follower, action=instance).save()\n\n\n@receiver(post_save, sender=Follow)\ndef add_permissions(*, instance, created, **_):\n    if created:\n        assign_perm(\"change_follow\", instance.user, instance)\n        assign_perm(\"delete_follow\", instance.user, instance)\n        assign_perm(\"view_follow\", instance.user, instance)\n\n\n@receiver(pre_delete, sender=Topic)\n@receiver(pre_delete, sender=Forum)\n@receiver(pre_delete, sender=Post)\ndef clean_up_follows(*, instance, **_):\n    ct = ContentType.objects.filter(\n        app_label=instance._meta.app_label, model=instance._meta.model_name\n    ).get()\n    Follow.objects.filter(content_type=ct, object_id=instance.pk).delete()\n", "path": "app/grandchallenge/notifications/signals.py"}, {"content": "from actstream.models import Follow\r\nfrom django import template\r\nfrom django.contrib.contenttypes.models import ContentType\r\n\r\nfrom grandchallenge.notifications.forms import FollowForm\r\n\r\nregister = template.Library()\r\n\r\n\r\n@register.simple_tag\r\ndef get_follow_object_pk(user, follow_object):\r\n    object_follows_for_user = Follow.objects.filter(\r\n        user=user,\r\n        content_type=ContentType.objects.get(\r\n            app_label=follow_object._meta.app_label,\r\n            model=follow_object._meta.model_name,\r\n        ),\r\n    ).all()\r\n\r\n    if not object_follows_for_user:\r\n        current_follow_object = []\r\n    else:\r\n        current_follow_object = []\r\n        for obj in object_follows_for_user:\r\n            if not obj.follow_object:\r\n                continue\r\n            elif obj.follow_object.id == follow_object.id:\r\n                current_follow_object = obj.pk\r\n    return current_follow_object\r\n\r\n\r\n@register.simple_tag\r\ndef follow_form(*, user, object_id, content_type):\r\n    return FollowForm(\r\n        user=user,\r\n        initial={\r\n            \"object_id\": object_id,\r\n            \"content_type\": content_type,\r\n            \"actor_only\": False,\r\n        },\r\n    )\r\n\r\n\r\n@register.simple_tag()\r\ndef get_content_type(follow_object):\r\n    try:\r\n        ct = ContentType.objects.get(\r\n            app_label=follow_object._meta.app_label,\r\n            model=follow_object._meta.model_name,\r\n        )\r\n    except AttributeError:\r\n        ct = None\r\n    return ct\r\n", "path": "app/grandchallenge/forum_conversation/templatetags/forum_extras.py"}]}