Coverage for website/facedetection/admin.py: 60.76%
71 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from django.contrib import admin, messages
2from django.db.models.query import Prefetch
3from django.urls import reverse
4from django.utils.html import format_html
5from django.utils.safestring import mark_safe
7from facedetection.services import trigger_facedetection_lambda
9from .models import (
10 FaceDetectionPhoto,
11 PhotoFaceEncoding,
12 ReferenceFace,
13 ReferenceFaceEncoding,
14)
17class ReferenceFaceEncodingInline(admin.TabularInline):
18 model = ReferenceFaceEncoding
19 readonly_fields = ["num_matches"]
20 fields = ["num_matches"]
21 can_delete = False
22 extra = 0
24 def has_add_permission(self, request, obj=None):
25 return False # Encodings should not be created manually.
27 def get_queryset(self, request):
28 return super().get_queryset(request).only("reference")
31@admin.register(ReferenceFace)
32class ReferenceFaceAdmin(admin.ModelAdmin):
33 list_display = [
34 "user",
35 "status",
36 "created_at",
37 "marked_for_deletion_at",
38 ]
40 search_fields = [
41 "user__username",
42 "user__first_name",
43 "user__last_name",
44 ]
46 list_filter = ["status", "marked_for_deletion_at"]
47 inlines = [ReferenceFaceEncodingInline]
49 actions = ["resubmit_reference_faces"]
51 def get_readonly_fields(self, request, obj=None):
52 if obj is None:
53 return ["created_at", "submitted_at", "status"]
54 return ["file", "user", "created_at", "submitted_at", "status"]
56 @admin.action(description="Resubmit reference faces for analysis.")
57 def resubmit_reference_faces(self, request, queryset) -> list[ReferenceFace]:
58 querylist = list(
59 queryset.filter(
60 status=FaceDetectionPhoto.Status.PROCESSING,
61 )
62 )
63 if querylist:
64 trigger_facedetection_lambda(querylist)
65 messages.success(request, "Resubmit successful.")
66 return querylist
69class PhotoFaceEncodingInline(admin.TabularInline):
70 model = PhotoFaceEncoding
71 readonly_fields = ["view_matches"]
72 fields = ["view_matches"]
73 can_delete = False
74 extra = 0
76 @admin.display(description="Matches")
77 def view_matches(self, obj):
78 reference_faces = [match.reference for match in obj.matches.all()]
79 if not reference_faces:
80 return "-"
82 links = [
83 format_html(
84 '<a href="{url}">{text}</a>',
85 url=reverse(
86 "admin:facedetection_referenceface_change",
87 kwargs={"object_id": rf.pk},
88 ),
89 text=str(rf),
90 )
91 for rf in reference_faces
92 ]
93 return mark_safe(", ".join(links))
95 def has_add_permission(self, request, obj=None):
96 return False # Encodings should not be created manually.
98 def get_queryset(self, request):
99 return (
100 super()
101 .get_queryset(request)
102 .only("photo") # Don't select the 128 encoding fields.
103 .prefetch_related(
104 "photo__photo__album",
105 Prefetch(
106 "matches",
107 queryset=ReferenceFaceEncoding.objects.select_related(
108 "reference", "reference__user"
109 ).only("reference"),
110 ),
111 )
112 )
115@admin.register(FaceDetectionPhoto)
116class FaceDetectionPhotoAdmin(admin.ModelAdmin):
117 list_display = [
118 "__str__",
119 "status",
120 "submitted_at",
121 "num_faces",
122 ]
124 readonly_fields = [
125 "photo",
126 "submitted_at",
127 "status",
128 ]
130 search_fields = [
131 "photo__album__title",
132 "photo__album__date",
133 "photo__file",
134 ]
136 list_filter = ["status", "submitted_at"]
137 inlines = [PhotoFaceEncodingInline]
139 actions = ["resubmit_face_detection_photos"]
141 def get_queryset(self, request):
142 return (
143 super()
144 .get_queryset(request)
145 .select_related("photo")
146 .prefetch_related("photo__album")
147 .select_properties("num_faces")
148 )
150 def has_add_permission(self, request):
151 return False
153 @admin.action(description="Resubmits face detection photos for analysis.")
154 def resubmit_face_detection_photos(
155 self, request, queryset
156 ) -> list[FaceDetectionPhoto]:
157 querylist = list(
158 queryset.filter(
159 status=FaceDetectionPhoto.Status.PROCESSING,
160 )
161 )
162 if querylist:
163 trigger_facedetection_lambda(querylist)
164 messages.success(request, "Resubmit successful.")
165 return querylist