We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Entry.DoesNotExist in RegistrationAdmin changeform
Sentry Issue: [CONCREXIT-Q5](https://thalia.sentry.io/issues/4058249887/?referrer=github_integration)

```
Entry.DoesNotExist: Entry matching query does not exist.
(5 additional frame(s) were not displayed)
...
  File "registrations/admin.py", line 169, in changeform_view
    obj = Entry.objects.get(id=object_id)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/registrations/admin.py`
Content:
```
1 """Registers admin interfaces for the registrations module."""
2 from functools import partial
3 
4 from django.contrib import admin
5 from django.forms import Field
6 from django.utils.translation import gettext_lazy as _
7 
8 from payments.widgets import PaymentWidget
9 from registrations.services import (
10     accept_registration,
11     accept_renewal,
12     reject_registration,
13     reject_renewal,
14 )
15 
16 from .forms import RegistrationAdminForm
17 from .models import Entry, Reference, Registration, Renewal
18 
19 
20 class ReferenceInline(admin.StackedInline):
21     model = Reference
22     extra = 0
23 
24 
25 @admin.register(Registration)
26 class RegistrationAdmin(admin.ModelAdmin):
27     """Manage the registrations."""
28 
29     list_display = (
30         "name",
31         "email",
32         "status",
33         "membership_type",
34         "contribution",
35         "created_at",
36         "payment",
37         "no_references",
38         "reference_count",
39     )
40     list_filter = (
41         "status",
42         "programme",
43         "membership_type",
44         "no_references",
45         "payment__type",
46         "contribution",
47     )
48     inlines = (ReferenceInline,)
49     search_fields = (
50         "first_name",
51         "last_name",
52         "email",
53         "phone_number",
54         "student_number",
55     )
56     date_hierarchy = "created_at"
57     fieldsets = (
58         (
59             _("Application information"),
60             {
61                 "fields": (
62                     "created_at",
63                     "updated_at",
64                     "username",
65                     "length",
66                     "contribution",
67                     "membership_type",
68                     "status",
69                     "payment",
70                     "remarks",
71                 )
72             },
73         ),
74         (
75             _("Personal information"),
76             {
77                 "fields": (
78                     "first_name",
79                     "last_name",
80                     "birthday",
81                     "optin_birthday",
82                     "email",
83                     "optin_mailinglist",
84                     "phone_number",
85                 )
86             },
87         ),
88         (
89             _("Address"),
90             {
91                 "fields": (
92                     "address_street",
93                     "address_street2",
94                     "address_postal_code",
95                     "address_city",
96                     "address_country",
97                 )
98             },
99         ),
100         (
101             _("Financial"),
102             {
103                 "fields": (
104                     "direct_debit",
105                     "initials",
106                     "iban",
107                     "bic",
108                     "signature",
109                 )
110             },
111         ),
112         (
113             _("University information"),
114             {
115                 "fields": (
116                     "student_number",
117                     "programme",
118                     "starting_year",
119                 )
120             },
121         ),
122     )
123 
124     form = RegistrationAdminForm
125 
126     actions = ["accept_registrations", "reject_registrations"]
127 
128     def get_actions(self, request):
129         actions = super().get_actions(request)
130 
131         if not request.user.has_perm("registrations.review_entries"):
132             if "accept_registrations" in actions:
133                 del actions["accept_registrations"]
134             if "reject_registrations" in actions:
135                 del actions["reject_registrations"]
136 
137         return actions
138 
139     @admin.action(description="Accept selected registrations")
140     def accept_registrations(self, request, queryset):  # pragma: no cover
141         if queryset.exclude(status=Registration.STATUS_REVIEW).exists():
142             self.message_user(
143                 request, "Only registrations in review can be accepted", "error"
144             )
145             return
146 
147         count = 0
148         for registration in queryset:
149             try:
150                 accept_registration(registration, actor=request.user)
151                 count += 1
152             except ValueError as e:
153                 self.message_user(
154                     request, f"Error accepting {registration}: {e.message}", "error"
155                 )
156 
157         self.message_user(request, f"Accepted {count} registrations", "success")
158 
159     @admin.action(description="Reject selected registrations")
160     def reject_registrations(self, request, queryset):  # pragma: no cover
161         if queryset.exclude(status=Registration.STATUS_REVIEW).exists():
162             self.message_user(
163                 request, "Only registrations in review can be rejected", "error"
164             )
165             return
166 
167         count = queryset.count()
168         for registration in queryset:
169             reject_registration(registration, actor=request.user)
170 
171         self.message_user(request, f"Rejected {count} registrations", "success")
172 
173     def reference_count(self, obj):
174         return obj.reference_set.count()
175 
176     reference_count.short_description = _("references")
177 
178     def get_form(self, request, obj=None, **kwargs):
179         return super().get_form(
180             request,
181             obj,
182             formfield_callback=partial(
183                 self.formfield_for_dbfield, request=request, obj=obj
184             ),
185             **kwargs,
186         )
187 
188     def formfield_for_dbfield(self, db_field, request, obj=None, **kwargs):
189         field = super().formfield_for_dbfield(db_field, request, **kwargs)
190         if db_field.name == "payment":
191             return Field(
192                 widget=PaymentWidget(obj=obj), initial=field.initial, required=False
193             )
194         return field
195 
196     def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
197         """Render the change formview.
198 
199         Only allow when the entry has not been processed yet
200         """
201         obj = None
202         can_review = False
203         can_resend = False
204         can_revert = False
205         if object_id is not None and request.user.has_perm(
206             "registrations.review_entries"
207         ):
208             obj = Entry.objects.get(id=object_id)
209             can_review = obj.status == Entry.STATUS_REVIEW
210             can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]
211             try:
212                 can_resend = obj.registration.status == Entry.STATUS_CONFIRM
213             except Registration.DoesNotExist:
214                 pass
215         return super().changeform_view(
216             request,
217             object_id,
218             form_url,
219             {
220                 "entry": obj,
221                 "can_review": can_review,
222                 "can_resend": can_resend,
223                 "can_revert": can_revert,
224             },
225         )
226 
227     def get_readonly_fields(self, request, obj=None):
228         if obj is None or obj.status not in (
229             Entry.STATUS_REJECTED,
230             Entry.STATUS_ACCEPTED,
231             Entry.STATUS_COMPLETED,
232         ):
233             return ["status", "created_at", "updated_at", "payment"]
234         return [
235             field.name
236             for field in self.model._meta.get_fields()
237             if field.name not in ["payment", "no_references"] and field.editable
238         ]
239 
240     @staticmethod
241     def name(obj):
242         return obj.get_full_name()
243 
244     def has_change_permission(self, request, obj=None):
245         """Completed registrations are read-only."""
246         return (
247             False
248             if obj and obj.status == Entry.STATUS_COMPLETED
249             else super().has_change_permission(request, obj)
250         )
251 
252     def has_add_permission(self, request):
253         return False
254 
255     def save_model(self, request, obj, form, change):
256         if obj.status not in (
257             Entry.STATUS_REJECTED,
258             Entry.STATUS_ACCEPTED,
259             Entry.STATUS_COMPLETED,
260         ):
261             super().save_model(request, obj, form, change)
262 
263 
264 @admin.register(Renewal)
265 class RenewalAdmin(RegistrationAdmin):
266     """Manage the renewals."""
267 
268     list_display = (
269         "name",
270         "email",
271         "status",
272         "membership_type",
273         "contribution",
274         "created_at",
275         "payment",
276         "no_references",
277         "reference_count",
278     )
279     list_filter = (
280         "status",
281         "membership_type",
282         "no_references",
283         "payment__type",
284         "contribution",
285     )
286     search_fields = (
287         "member__first_name",
288         "member__last_name",
289         "member__email",
290         "member__profile__phone_number",
291         "member__profile__student_number",
292     )
293     date_hierarchy = "created_at"
294     fieldsets = (
295         (
296             _("Application information"),
297             {
298                 "fields": (
299                     "created_at",
300                     "updated_at",
301                     "length",
302                     "contribution",
303                     "membership_type",
304                     "status",
305                     "payment",
306                     "remarks",
307                     "member",
308                 )
309             },
310         ),
311     )
312 
313     actions = ["accept_renewals", "reject_renewals"]
314 
315     def get_actions(self, request):
316         actions = super().get_actions(request)
317 
318         if not request.user.has_perm("registrations.review_entries"):
319             if "accept_renewals" in actions:  # pragma: no cover
320                 del actions["accept_renewals"]
321             if "reject_renewals" in actions:  # pragma: no cover
322                 del actions["reject_renewals"]
323 
324         return actions
325 
326     @admin.action(description="Accept selected renewals")
327     def accept_renewals(self, request, queryset):  # pragma: no cover
328         if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():
329             self.message_user(
330                 request, "Only renewals in review can be accepted", "error"
331             )
332             return
333 
334         count = queryset.count()
335         for renewal in queryset:
336             accept_renewal(renewal, actor=request.user)
337             count += 1
338 
339         self.message_user(request, f"Accepted {count} renewals", "success")
340 
341     @admin.action(description="Reject selected renewals")
342     def reject_renewals(self, request, queryset):  # pragma: no cover
343         if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():
344             self.message_user(
345                 request, "Only renewals in review can be rejected", "error"
346             )
347             return
348 
349         count = queryset.count()
350         for renewal in queryset:
351             reject_renewal(renewal, actor=request.user)
352 
353         self.message_user(request, f"Rejected {count} renewals", "success")
354 
355     def get_readonly_fields(self, request, obj=None):
356         """Make all fields read-only and add member if needed."""
357         fields = super().get_readonly_fields(request, obj)
358         if "member" not in fields and obj is not None:
359             return fields + ["member"]
360         return fields
361 
362     def has_add_permission(self, request):
363         return False
364 
365     @staticmethod
366     def name(obj):
367         return obj.member.get_full_name()
368 
369     name.short_description = _("name")
370 
371     @staticmethod
372     def email(obj):
373         return obj.member.email
374
```
--- 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/website/registrations/admin.py b/website/registrations/admin.py
--- a/website/registrations/admin.py
+++ b/website/registrations/admin.py
@@ -204,14 +204,18 @@
         can_revert = False
         if object_id is not None and request.user.has_perm(
             "registrations.review_entries"
-        ):
-            obj = Entry.objects.get(id=object_id)
+        ):  # pragma: no cover
+            obj = self.get_object(request, object_id)
+            if obj is None:
+                return self._get_obj_does_not_exist_redirect(
+                    request, self.opts, object_id
+                )
             can_review = obj.status == Entry.STATUS_REVIEW
             can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]
-            try:
-                can_resend = obj.registration.status == Entry.STATUS_CONFIRM
-            except Registration.DoesNotExist:
-                pass
+            can_resend = obj.status == Entry.STATUS_CONFIRM and isinstance(
+                obj, Registration
+            )
+
         return super().changeform_view(
             request,
             object_id,

{"golden_diff": "diff --git a/website/registrations/admin.py b/website/registrations/admin.py\n--- a/website/registrations/admin.py\n+++ b/website/registrations/admin.py\n@@ -204,14 +204,18 @@\n         can_revert = False\n         if object_id is not None and request.user.has_perm(\n             \"registrations.review_entries\"\n-        ):\n-            obj = Entry.objects.get(id=object_id)\n+        ):  # pragma: no cover\n+            obj = self.get_object(request, object_id)\n+            if obj is None:\n+                return self._get_obj_does_not_exist_redirect(\n+                    request, self.opts, object_id\n+                )\n             can_review = obj.status == Entry.STATUS_REVIEW\n             can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]\n-            try:\n-                can_resend = obj.registration.status == Entry.STATUS_CONFIRM\n-            except Registration.DoesNotExist:\n-                pass\n+            can_resend = obj.status == Entry.STATUS_CONFIRM and isinstance(\n+                obj, Registration\n+            )\n+\n         return super().changeform_view(\n             request,\n             object_id,\n", "issue": "Entry.DoesNotExist in RegistrationAdmin changeform\nSentry Issue: [CONCREXIT-Q5](https://thalia.sentry.io/issues/4058249887/?referrer=github_integration)\n\n```\nEntry.DoesNotExist: Entry matching query does not exist.\n(5 additional frame(s) were not displayed)\n...\n  File \"registrations/admin.py\", line 169, in changeform_view\n    obj = Entry.objects.get(id=object_id)\n```\n", "before_files": [{"content": "\"\"\"Registers admin interfaces for the registrations module.\"\"\"\nfrom functools import partial\n\nfrom django.contrib import admin\nfrom django.forms import Field\nfrom django.utils.translation import gettext_lazy as _\n\nfrom payments.widgets import PaymentWidget\nfrom registrations.services import (\n    accept_registration,\n    accept_renewal,\n    reject_registration,\n    reject_renewal,\n)\n\nfrom .forms import RegistrationAdminForm\nfrom .models import Entry, Reference, Registration, Renewal\n\n\nclass ReferenceInline(admin.StackedInline):\n    model = Reference\n    extra = 0\n\n\n@admin.register(Registration)\nclass RegistrationAdmin(admin.ModelAdmin):\n    \"\"\"Manage the registrations.\"\"\"\n\n    list_display = (\n        \"name\",\n        \"email\",\n        \"status\",\n        \"membership_type\",\n        \"contribution\",\n        \"created_at\",\n        \"payment\",\n        \"no_references\",\n        \"reference_count\",\n    )\n    list_filter = (\n        \"status\",\n        \"programme\",\n        \"membership_type\",\n        \"no_references\",\n        \"payment__type\",\n        \"contribution\",\n    )\n    inlines = (ReferenceInline,)\n    search_fields = (\n        \"first_name\",\n        \"last_name\",\n        \"email\",\n        \"phone_number\",\n        \"student_number\",\n    )\n    date_hierarchy = \"created_at\"\n    fieldsets = (\n        (\n            _(\"Application information\"),\n            {\n                \"fields\": (\n                    \"created_at\",\n                    \"updated_at\",\n                    \"username\",\n                    \"length\",\n                    \"contribution\",\n                    \"membership_type\",\n                    \"status\",\n                    \"payment\",\n                    \"remarks\",\n                )\n            },\n        ),\n        (\n            _(\"Personal information\"),\n            {\n                \"fields\": (\n                    \"first_name\",\n                    \"last_name\",\n                    \"birthday\",\n                    \"optin_birthday\",\n                    \"email\",\n                    \"optin_mailinglist\",\n                    \"phone_number\",\n                )\n            },\n        ),\n        (\n            _(\"Address\"),\n            {\n                \"fields\": (\n                    \"address_street\",\n                    \"address_street2\",\n                    \"address_postal_code\",\n                    \"address_city\",\n                    \"address_country\",\n                )\n            },\n        ),\n        (\n            _(\"Financial\"),\n            {\n                \"fields\": (\n                    \"direct_debit\",\n                    \"initials\",\n                    \"iban\",\n                    \"bic\",\n                    \"signature\",\n                )\n            },\n        ),\n        (\n            _(\"University information\"),\n            {\n                \"fields\": (\n                    \"student_number\",\n                    \"programme\",\n                    \"starting_year\",\n                )\n            },\n        ),\n    )\n\n    form = RegistrationAdminForm\n\n    actions = [\"accept_registrations\", \"reject_registrations\"]\n\n    def get_actions(self, request):\n        actions = super().get_actions(request)\n\n        if not request.user.has_perm(\"registrations.review_entries\"):\n            if \"accept_registrations\" in actions:\n                del actions[\"accept_registrations\"]\n            if \"reject_registrations\" in actions:\n                del actions[\"reject_registrations\"]\n\n        return actions\n\n    @admin.action(description=\"Accept selected registrations\")\n    def accept_registrations(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Registration.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only registrations in review can be accepted\", \"error\"\n            )\n            return\n\n        count = 0\n        for registration in queryset:\n            try:\n                accept_registration(registration, actor=request.user)\n                count += 1\n            except ValueError as e:\n                self.message_user(\n                    request, f\"Error accepting {registration}: {e.message}\", \"error\"\n                )\n\n        self.message_user(request, f\"Accepted {count} registrations\", \"success\")\n\n    @admin.action(description=\"Reject selected registrations\")\n    def reject_registrations(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Registration.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only registrations in review can be rejected\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for registration in queryset:\n            reject_registration(registration, actor=request.user)\n\n        self.message_user(request, f\"Rejected {count} registrations\", \"success\")\n\n    def reference_count(self, obj):\n        return obj.reference_set.count()\n\n    reference_count.short_description = _(\"references\")\n\n    def get_form(self, request, obj=None, **kwargs):\n        return super().get_form(\n            request,\n            obj,\n            formfield_callback=partial(\n                self.formfield_for_dbfield, request=request, obj=obj\n            ),\n            **kwargs,\n        )\n\n    def formfield_for_dbfield(self, db_field, request, obj=None, **kwargs):\n        field = super().formfield_for_dbfield(db_field, request, **kwargs)\n        if db_field.name == \"payment\":\n            return Field(\n                widget=PaymentWidget(obj=obj), initial=field.initial, required=False\n            )\n        return field\n\n    def changeform_view(self, request, object_id=None, form_url=\"\", extra_context=None):\n        \"\"\"Render the change formview.\n\n        Only allow when the entry has not been processed yet\n        \"\"\"\n        obj = None\n        can_review = False\n        can_resend = False\n        can_revert = False\n        if object_id is not None and request.user.has_perm(\n            \"registrations.review_entries\"\n        ):\n            obj = Entry.objects.get(id=object_id)\n            can_review = obj.status == Entry.STATUS_REVIEW\n            can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]\n            try:\n                can_resend = obj.registration.status == Entry.STATUS_CONFIRM\n            except Registration.DoesNotExist:\n                pass\n        return super().changeform_view(\n            request,\n            object_id,\n            form_url,\n            {\n                \"entry\": obj,\n                \"can_review\": can_review,\n                \"can_resend\": can_resend,\n                \"can_revert\": can_revert,\n            },\n        )\n\n    def get_readonly_fields(self, request, obj=None):\n        if obj is None or obj.status not in (\n            Entry.STATUS_REJECTED,\n            Entry.STATUS_ACCEPTED,\n            Entry.STATUS_COMPLETED,\n        ):\n            return [\"status\", \"created_at\", \"updated_at\", \"payment\"]\n        return [\n            field.name\n            for field in self.model._meta.get_fields()\n            if field.name not in [\"payment\", \"no_references\"] and field.editable\n        ]\n\n    @staticmethod\n    def name(obj):\n        return obj.get_full_name()\n\n    def has_change_permission(self, request, obj=None):\n        \"\"\"Completed registrations are read-only.\"\"\"\n        return (\n            False\n            if obj and obj.status == Entry.STATUS_COMPLETED\n            else super().has_change_permission(request, obj)\n        )\n\n    def has_add_permission(self, request):\n        return False\n\n    def save_model(self, request, obj, form, change):\n        if obj.status not in (\n            Entry.STATUS_REJECTED,\n            Entry.STATUS_ACCEPTED,\n            Entry.STATUS_COMPLETED,\n        ):\n            super().save_model(request, obj, form, change)\n\n\n@admin.register(Renewal)\nclass RenewalAdmin(RegistrationAdmin):\n    \"\"\"Manage the renewals.\"\"\"\n\n    list_display = (\n        \"name\",\n        \"email\",\n        \"status\",\n        \"membership_type\",\n        \"contribution\",\n        \"created_at\",\n        \"payment\",\n        \"no_references\",\n        \"reference_count\",\n    )\n    list_filter = (\n        \"status\",\n        \"membership_type\",\n        \"no_references\",\n        \"payment__type\",\n        \"contribution\",\n    )\n    search_fields = (\n        \"member__first_name\",\n        \"member__last_name\",\n        \"member__email\",\n        \"member__profile__phone_number\",\n        \"member__profile__student_number\",\n    )\n    date_hierarchy = \"created_at\"\n    fieldsets = (\n        (\n            _(\"Application information\"),\n            {\n                \"fields\": (\n                    \"created_at\",\n                    \"updated_at\",\n                    \"length\",\n                    \"contribution\",\n                    \"membership_type\",\n                    \"status\",\n                    \"payment\",\n                    \"remarks\",\n                    \"member\",\n                )\n            },\n        ),\n    )\n\n    actions = [\"accept_renewals\", \"reject_renewals\"]\n\n    def get_actions(self, request):\n        actions = super().get_actions(request)\n\n        if not request.user.has_perm(\"registrations.review_entries\"):\n            if \"accept_renewals\" in actions:  # pragma: no cover\n                del actions[\"accept_renewals\"]\n            if \"reject_renewals\" in actions:  # pragma: no cover\n                del actions[\"reject_renewals\"]\n\n        return actions\n\n    @admin.action(description=\"Accept selected renewals\")\n    def accept_renewals(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only renewals in review can be accepted\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for renewal in queryset:\n            accept_renewal(renewal, actor=request.user)\n            count += 1\n\n        self.message_user(request, f\"Accepted {count} renewals\", \"success\")\n\n    @admin.action(description=\"Reject selected renewals\")\n    def reject_renewals(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only renewals in review can be rejected\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for renewal in queryset:\n            reject_renewal(renewal, actor=request.user)\n\n        self.message_user(request, f\"Rejected {count} renewals\", \"success\")\n\n    def get_readonly_fields(self, request, obj=None):\n        \"\"\"Make all fields read-only and add member if needed.\"\"\"\n        fields = super().get_readonly_fields(request, obj)\n        if \"member\" not in fields and obj is not None:\n            return fields + [\"member\"]\n        return fields\n\n    def has_add_permission(self, request):\n        return False\n\n    @staticmethod\n    def name(obj):\n        return obj.member.get_full_name()\n\n    name.short_description = _(\"name\")\n\n    @staticmethod\n    def email(obj):\n        return obj.member.email\n", "path": "website/registrations/admin.py"}], "after_files": [{"content": "\"\"\"Registers admin interfaces for the registrations module.\"\"\"\nfrom functools import partial\n\nfrom django.contrib import admin\nfrom django.forms import Field\nfrom django.utils.translation import gettext_lazy as _\n\nfrom payments.widgets import PaymentWidget\nfrom registrations.services import (\n    accept_registration,\n    accept_renewal,\n    reject_registration,\n    reject_renewal,\n)\n\nfrom .forms import RegistrationAdminForm\nfrom .models import Entry, Reference, Registration, Renewal\n\n\nclass ReferenceInline(admin.StackedInline):\n    model = Reference\n    extra = 0\n\n\n@admin.register(Registration)\nclass RegistrationAdmin(admin.ModelAdmin):\n    \"\"\"Manage the registrations.\"\"\"\n\n    list_display = (\n        \"name\",\n        \"email\",\n        \"status\",\n        \"membership_type\",\n        \"contribution\",\n        \"created_at\",\n        \"payment\",\n        \"no_references\",\n        \"reference_count\",\n    )\n    list_filter = (\n        \"status\",\n        \"programme\",\n        \"membership_type\",\n        \"no_references\",\n        \"payment__type\",\n        \"contribution\",\n    )\n    inlines = (ReferenceInline,)\n    search_fields = (\n        \"first_name\",\n        \"last_name\",\n        \"email\",\n        \"phone_number\",\n        \"student_number\",\n    )\n    date_hierarchy = \"created_at\"\n    fieldsets = (\n        (\n            _(\"Application information\"),\n            {\n                \"fields\": (\n                    \"created_at\",\n                    \"updated_at\",\n                    \"username\",\n                    \"length\",\n                    \"contribution\",\n                    \"membership_type\",\n                    \"status\",\n                    \"payment\",\n                    \"remarks\",\n                )\n            },\n        ),\n        (\n            _(\"Personal information\"),\n            {\n                \"fields\": (\n                    \"first_name\",\n                    \"last_name\",\n                    \"birthday\",\n                    \"optin_birthday\",\n                    \"email\",\n                    \"optin_mailinglist\",\n                    \"phone_number\",\n                )\n            },\n        ),\n        (\n            _(\"Address\"),\n            {\n                \"fields\": (\n                    \"address_street\",\n                    \"address_street2\",\n                    \"address_postal_code\",\n                    \"address_city\",\n                    \"address_country\",\n                )\n            },\n        ),\n        (\n            _(\"Financial\"),\n            {\n                \"fields\": (\n                    \"direct_debit\",\n                    \"initials\",\n                    \"iban\",\n                    \"bic\",\n                    \"signature\",\n                )\n            },\n        ),\n        (\n            _(\"University information\"),\n            {\n                \"fields\": (\n                    \"student_number\",\n                    \"programme\",\n                    \"starting_year\",\n                )\n            },\n        ),\n    )\n\n    form = RegistrationAdminForm\n\n    actions = [\"accept_registrations\", \"reject_registrations\"]\n\n    def get_actions(self, request):\n        actions = super().get_actions(request)\n\n        if not request.user.has_perm(\"registrations.review_entries\"):\n            if \"accept_registrations\" in actions:\n                del actions[\"accept_registrations\"]\n            if \"reject_registrations\" in actions:\n                del actions[\"reject_registrations\"]\n\n        return actions\n\n    @admin.action(description=\"Accept selected registrations\")\n    def accept_registrations(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Registration.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only registrations in review can be accepted\", \"error\"\n            )\n            return\n\n        count = 0\n        for registration in queryset:\n            try:\n                accept_registration(registration, actor=request.user)\n                count += 1\n            except ValueError as e:\n                self.message_user(\n                    request, f\"Error accepting {registration}: {e.message}\", \"error\"\n                )\n\n        self.message_user(request, f\"Accepted {count} registrations\", \"success\")\n\n    @admin.action(description=\"Reject selected registrations\")\n    def reject_registrations(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Registration.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only registrations in review can be rejected\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for registration in queryset:\n            reject_registration(registration, actor=request.user)\n\n        self.message_user(request, f\"Rejected {count} registrations\", \"success\")\n\n    def reference_count(self, obj):\n        return obj.reference_set.count()\n\n    reference_count.short_description = _(\"references\")\n\n    def get_form(self, request, obj=None, **kwargs):\n        return super().get_form(\n            request,\n            obj,\n            formfield_callback=partial(\n                self.formfield_for_dbfield, request=request, obj=obj\n            ),\n            **kwargs,\n        )\n\n    def formfield_for_dbfield(self, db_field, request, obj=None, **kwargs):\n        field = super().formfield_for_dbfield(db_field, request, **kwargs)\n        if db_field.name == \"payment\":\n            return Field(\n                widget=PaymentWidget(obj=obj), initial=field.initial, required=False\n            )\n        return field\n\n    def changeform_view(self, request, object_id=None, form_url=\"\", extra_context=None):\n        \"\"\"Render the change formview.\n\n        Only allow when the entry has not been processed yet\n        \"\"\"\n        obj = None\n        can_review = False\n        can_resend = False\n        can_revert = False\n        if object_id is not None and request.user.has_perm(\n            \"registrations.review_entries\"\n        ):  # pragma: no cover\n            obj = self.get_object(request, object_id)\n            if obj is None:\n                return self._get_obj_does_not_exist_redirect(\n                    request, self.opts, object_id\n                )\n            can_review = obj.status == Entry.STATUS_REVIEW\n            can_revert = obj.status in [Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]\n            can_resend = obj.status == Entry.STATUS_CONFIRM and isinstance(\n                obj, Registration\n            )\n\n        return super().changeform_view(\n            request,\n            object_id,\n            form_url,\n            {\n                \"entry\": obj,\n                \"can_review\": can_review,\n                \"can_resend\": can_resend,\n                \"can_revert\": can_revert,\n            },\n        )\n\n    def get_readonly_fields(self, request, obj=None):\n        if obj is None or obj.status not in (\n            Entry.STATUS_REJECTED,\n            Entry.STATUS_ACCEPTED,\n            Entry.STATUS_COMPLETED,\n        ):\n            return [\"status\", \"created_at\", \"updated_at\", \"payment\"]\n        return [\n            field.name\n            for field in self.model._meta.get_fields()\n            if field.name not in [\"payment\", \"no_references\"] and field.editable\n        ]\n\n    @staticmethod\n    def name(obj):\n        return obj.get_full_name()\n\n    def has_change_permission(self, request, obj=None):\n        \"\"\"Completed registrations are read-only.\"\"\"\n        return (\n            False\n            if obj and obj.status == Entry.STATUS_COMPLETED\n            else super().has_change_permission(request, obj)\n        )\n\n    def has_add_permission(self, request):\n        return False\n\n    def save_model(self, request, obj, form, change):\n        if obj.status not in (\n            Entry.STATUS_REJECTED,\n            Entry.STATUS_ACCEPTED,\n            Entry.STATUS_COMPLETED,\n        ):\n            super().save_model(request, obj, form, change)\n\n\n@admin.register(Renewal)\nclass RenewalAdmin(RegistrationAdmin):\n    \"\"\"Manage the renewals.\"\"\"\n\n    list_display = (\n        \"name\",\n        \"email\",\n        \"status\",\n        \"membership_type\",\n        \"contribution\",\n        \"created_at\",\n        \"payment\",\n        \"no_references\",\n        \"reference_count\",\n    )\n    list_filter = (\n        \"status\",\n        \"membership_type\",\n        \"no_references\",\n        \"payment__type\",\n        \"contribution\",\n    )\n    search_fields = (\n        \"member__first_name\",\n        \"member__last_name\",\n        \"member__email\",\n        \"member__profile__phone_number\",\n        \"member__profile__student_number\",\n    )\n    date_hierarchy = \"created_at\"\n    fieldsets = (\n        (\n            _(\"Application information\"),\n            {\n                \"fields\": (\n                    \"created_at\",\n                    \"updated_at\",\n                    \"length\",\n                    \"contribution\",\n                    \"membership_type\",\n                    \"status\",\n                    \"payment\",\n                    \"remarks\",\n                    \"member\",\n                )\n            },\n        ),\n    )\n\n    actions = [\"accept_renewals\", \"reject_renewals\"]\n\n    def get_actions(self, request):\n        actions = super().get_actions(request)\n\n        if not request.user.has_perm(\"registrations.review_entries\"):\n            if \"accept_renewals\" in actions:  # pragma: no cover\n                del actions[\"accept_renewals\"]\n            if \"reject_renewals\" in actions:  # pragma: no cover\n                del actions[\"reject_renewals\"]\n\n        return actions\n\n    @admin.action(description=\"Accept selected renewals\")\n    def accept_renewals(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only renewals in review can be accepted\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for renewal in queryset:\n            accept_renewal(renewal, actor=request.user)\n            count += 1\n\n        self.message_user(request, f\"Accepted {count} renewals\", \"success\")\n\n    @admin.action(description=\"Reject selected renewals\")\n    def reject_renewals(self, request, queryset):  # pragma: no cover\n        if queryset.exclude(status=Renewal.STATUS_REVIEW).exists():\n            self.message_user(\n                request, \"Only renewals in review can be rejected\", \"error\"\n            )\n            return\n\n        count = queryset.count()\n        for renewal in queryset:\n            reject_renewal(renewal, actor=request.user)\n\n        self.message_user(request, f\"Rejected {count} renewals\", \"success\")\n\n    def get_readonly_fields(self, request, obj=None):\n        \"\"\"Make all fields read-only and add member if needed.\"\"\"\n        fields = super().get_readonly_fields(request, obj)\n        if \"member\" not in fields and obj is not None:\n            return fields + [\"member\"]\n        return fields\n\n    def has_add_permission(self, request):\n        return False\n\n    @staticmethod\n    def name(obj):\n        return obj.member.get_full_name()\n\n    name.short_description = _(\"name\")\n\n    @staticmethod\n    def email(obj):\n        return obj.member.email\n", "path": "website/registrations/admin.py"}]}