|
10 | 10 | OrdinalTypeEnum, |
11 | 11 | Question, |
12 | 12 | QuestionTypeEnum, |
| 13 | + RecommendationResult, |
13 | 14 | Tool, |
14 | 15 | ToolAnswer, |
| 16 | + UserAnswer, |
| 17 | + UserSubmission, |
15 | 18 | ) |
16 | 19 |
|
17 | 20 |
|
@@ -244,9 +247,12 @@ class ToolAdmin(UserResourceAdmin, admin.ModelAdmin): # type: ignore[reportMiss |
244 | 247 | "Basic Information", |
245 | 248 | { |
246 | 249 | "fields": ( |
247 | | - "catalog", "name", |
248 | | - "tagline", "description", |
249 | | - "video_link", "tool_link", |
| 250 | + "catalog", |
| 251 | + "name", |
| 252 | + "tagline", |
| 253 | + "description", |
| 254 | + "video_link", |
| 255 | + "tool_link", |
250 | 256 | "logo", |
251 | 257 | ), |
252 | 258 | }, |
@@ -278,3 +284,113 @@ def save_model(self, request, obj, form, change): # type: ignore[reportMissingT |
278 | 284 | else None, |
279 | 285 | }, |
280 | 286 | ) |
| 287 | + |
| 288 | + |
| 289 | +# ============================================================================ |
| 290 | +# User Submission Models Admin |
| 291 | +# ============================================================================ |
| 292 | + |
| 293 | + |
| 294 | +class UserAnswerInline(admin.TabularInline): # type: ignore[reportMissingTypeArgument] |
| 295 | + model = UserAnswer |
| 296 | + extra = 0 |
| 297 | + fields = ["question", "ordinal_value", "get_selected_options"] |
| 298 | + readonly_fields = ["get_selected_options"] |
| 299 | + ordering = ["question__order"] |
| 300 | + |
| 301 | + @admin.display(description="Checkbox Options") |
| 302 | + def get_selected_options(self, obj: UserAnswer): |
| 303 | + if obj.pk and obj.question.question_type == "checkbox": |
| 304 | + return ", ".join([opt.text for opt in obj.selected_options.all()]) |
| 305 | + return "-" |
| 306 | + |
| 307 | + |
| 308 | +class RecommendationResultInline(admin.TabularInline): # type: ignore[reportMissingTypeArgument] |
| 309 | + model = RecommendationResult |
| 310 | + extra = 0 |
| 311 | + fields = ["rank", "tool", "score"] |
| 312 | + ordering = ["rank"] |
| 313 | + |
| 314 | + |
| 315 | +@admin.register(UserSubmission) |
| 316 | +class UserSubmissionAdmin(admin.ModelAdmin): # type: ignore[reportMissingTypeArgument] |
| 317 | + list_display = ["id", "catalog", "created_at", "answer_count", "recommendation_count"] |
| 318 | + list_filter = ["catalog", "created_at"] |
| 319 | + readonly_fields = ["id", "created_at"] |
| 320 | + fields = ["id", "catalog"] |
| 321 | + inlines = [UserAnswerInline, RecommendationResultInline] |
| 322 | + |
| 323 | + @admin.display(description="Answers") |
| 324 | + def answer_count(self, obj: UserSubmission): |
| 325 | + return obj.answers.count() |
| 326 | + |
| 327 | + @admin.display(description="Results") |
| 328 | + def recommendation_count(self, obj: UserSubmission): |
| 329 | + return obj.results.count() |
| 330 | + |
| 331 | + |
| 332 | +@admin.register(UserAnswer) |
| 333 | +class UserAnswerAdmin(admin.ModelAdmin): # type: ignore[reportMissingTypeArgument] |
| 334 | + list_display = ["submission_id", "question", "question_type", "get_answer"] |
| 335 | + list_filter = ["submission__catalog", "question__question_type"] |
| 336 | + search_fields = ["submission__id", "question__title"] |
| 337 | + |
| 338 | + def get_fields(self, request, obj=None): # type: ignore[reportMissingTypeArgument] |
| 339 | + """Show only relevant fields based on question type""" |
| 340 | + base_fields = ["submission", "question"] |
| 341 | + if obj and obj.question.question_type == "ordinal": |
| 342 | + return base_fields + ["ordinal_value"] |
| 343 | + if obj and obj.question.question_type == "checkbox": |
| 344 | + return base_fields + ["selected_options"] |
| 345 | + return base_fields + ["ordinal_value", "selected_options"] |
| 346 | + |
| 347 | + def get_form(self, request, obj=None, **kwargs): # type: ignore[reportMissingTypeArgument] |
| 348 | + form = super().get_form(request, obj, **kwargs) |
| 349 | + if obj and obj.question.question_type == "checkbox": |
| 350 | + self.filter_horizontal = ["selected_options"] |
| 351 | + else: |
| 352 | + self.filter_horizontal = [] |
| 353 | + return form |
| 354 | + |
| 355 | + @admin.display(description="Submission") |
| 356 | + def submission_id(self, obj: UserAnswer): |
| 357 | + return str(obj.submission.id)[:8] + "..." |
| 358 | + |
| 359 | + @admin.display(description="Type") |
| 360 | + def question_type(self, obj: UserAnswer): |
| 361 | + return obj.question.get_question_type_display() |
| 362 | + |
| 363 | + @admin.display(description="Answer") |
| 364 | + def get_answer(self, obj: UserAnswer): |
| 365 | + if obj.question.question_type == "ordinal": |
| 366 | + return obj.ordinal_value or "-" |
| 367 | + options = obj.selected_options.all() |
| 368 | + return ", ".join([opt.text for opt in options]) if options else "(none)" |
| 369 | + |
| 370 | + def formfield_for_manytomany(self, db_field, request, **kwargs): # type: ignore[reportMissingTypeArgument] |
| 371 | + if db_field.name == "selected_options": |
| 372 | + user_answer_id = request.resolver_match.kwargs.get("object_id") # type: ignore[reportOptionsArgumentAccess] |
| 373 | + if user_answer_id: |
| 374 | + try: |
| 375 | + user_answer = UserAnswer.objects.get(pk=user_answer_id) |
| 376 | + kwargs["queryset"] = CheckboxOption.objects.filter(question=user_answer.question) |
| 377 | + except UserAnswer.DoesNotExist: |
| 378 | + pass |
| 379 | + return super().formfield_for_manytomany(db_field, request, **kwargs) |
| 380 | + |
| 381 | + |
| 382 | +@admin.register(RecommendationResult) |
| 383 | +class RecommendationResultAdmin(admin.ModelAdmin): # type: ignore[reportMissingTypeArgument] |
| 384 | + list_display = ["submission_short", "rank", "tool", "score", "catalog"] |
| 385 | + list_filter = ["submission__catalog", "rank"] |
| 386 | + search_fields = ["submission__id", "tool__name"] |
| 387 | + ordering = ["submission", "rank"] |
| 388 | + fields = ["submission", "tool", "rank", "score"] |
| 389 | + |
| 390 | + @admin.display(description="Submission") |
| 391 | + def submission_short(self, obj: RecommendationResult): |
| 392 | + return str(obj.submission.id)[:8] + "..." |
| 393 | + |
| 394 | + @admin.display(description="Catalog") |
| 395 | + def catalog(self, obj: RecommendationResult): |
| 396 | + return obj.submission.catalog.name |
0 commit comments