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

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 

6 

7from facedetection.services import trigger_facedetection_lambda 

8 

9from .models import ( 

10 FaceDetectionPhoto, 

11 PhotoFaceEncoding, 

12 ReferenceFace, 

13 ReferenceFaceEncoding, 

14) 

15 

16 

17class ReferenceFaceEncodingInline(admin.TabularInline): 

18 model = ReferenceFaceEncoding 

19 readonly_fields = ["num_matches"] 

20 fields = ["num_matches"] 

21 can_delete = False 

22 extra = 0 

23 

24 def has_add_permission(self, request, obj=None): 

25 return False # Encodings should not be created manually. 

26 

27 def get_queryset(self, request): 

28 return super().get_queryset(request).only("reference") 

29 

30 

31@admin.register(ReferenceFace) 

32class ReferenceFaceAdmin(admin.ModelAdmin): 

33 list_display = [ 

34 "user", 

35 "status", 

36 "created_at", 

37 "marked_for_deletion_at", 

38 ] 

39 

40 search_fields = [ 

41 "user__username", 

42 "user__first_name", 

43 "user__last_name", 

44 ] 

45 

46 list_filter = ["status", "marked_for_deletion_at"] 

47 inlines = [ReferenceFaceEncodingInline] 

48 

49 actions = ["resubmit_reference_faces"] 

50 

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"] 

55 

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 

67 

68 

69class PhotoFaceEncodingInline(admin.TabularInline): 

70 model = PhotoFaceEncoding 

71 readonly_fields = ["view_matches"] 

72 fields = ["view_matches"] 

73 can_delete = False 

74 extra = 0 

75 

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 "-" 

81 

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)) 

94 

95 def has_add_permission(self, request, obj=None): 

96 return False # Encodings should not be created manually. 

97 

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 ) 

113 

114 

115@admin.register(FaceDetectionPhoto) 

116class FaceDetectionPhotoAdmin(admin.ModelAdmin): 

117 list_display = [ 

118 "__str__", 

119 "status", 

120 "submitted_at", 

121 "num_faces", 

122 ] 

123 

124 readonly_fields = [ 

125 "photo", 

126 "submitted_at", 

127 "status", 

128 ] 

129 

130 search_fields = [ 

131 "photo__album__title", 

132 "photo__album__date", 

133 "photo__file", 

134 ] 

135 

136 list_filter = ["status", "submitted_at"] 

137 inlines = [PhotoFaceEncodingInline] 

138 

139 actions = ["resubmit_face_detection_photos"] 

140 

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 ) 

149 

150 def has_add_permission(self, request): 

151 return False 

152 

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