Repository: comic/grand-challenge.org

Issue:
Algorithm Results API improvements
We would like to:

- [x] Get all of the results for a particular algorithm (filtered by the users permissions)
- [x] For an algorithm result, get a list of the output files, the metrics json, and the input files (without going through the job)
- [ ] Extract data from the metrics json (#1070)
- [x] Ensure the API is fast, check the number of db calls



Discussion:

Resolving patch:
diff --git a/app/grandchallenge/algorithms/serializers.py b/app/grandchallenge/algorithms/serializers.py
--- a/app/grandchallenge/algorithms/serializers.py
+++ b/app/grandchallenge/algorithms/serializers.py
@@ -48,31 +48,6 @@ class Meta:
         fields = ["pk", "api_url", "algorithm"]
 
 
-class ResultSerializer(serializers.ModelSerializer):
-    job = HyperlinkedRelatedField(
-        read_only=True, view_name="api:algorithms-job-detail"
-    )
-    images = HyperlinkedRelatedField(
-        many=True, read_only=True, view_name="api:image-detail"
-    )
-    import_session = HyperlinkedRelatedField(
-        source="rawimageuploadsession",
-        read_only=True,
-        view_name="api:upload-session-detail",
-    )
-
-    class Meta:
-        model = Result
-        fields = [
-            "pk",
-            "api_url",
-            "job",
-            "images",
-            "output",
-            "import_session",
-        ]
-
-
 class JobSerializer(serializers.ModelSerializer):
     algorithm_image = HyperlinkedRelatedField(
         queryset=AlgorithmImage.objects.all(),
@@ -99,3 +74,26 @@ class Meta:
         swagger_schema_fields = swagger_schema_fields_for_charfield(
             status=model._meta.get_field("status")
         )
+
+
+class ResultSerializer(serializers.ModelSerializer):
+    job = JobSerializer()
+    images = HyperlinkedRelatedField(
+        many=True, read_only=True, view_name="api:image-detail"
+    )
+    import_session = HyperlinkedRelatedField(
+        source="rawimageuploadsession",
+        read_only=True,
+        view_name="api:upload-session-detail",
+    )
+
+    class Meta:
+        model = Result
+        fields = [
+            "pk",
+            "api_url",
+            "job",
+            "images",
+            "output",
+            "import_session",
+        ]
diff --git a/app/grandchallenge/algorithms/views.py b/app/grandchallenge/algorithms/views.py
--- a/app/grandchallenge/algorithms/views.py
+++ b/app/grandchallenge/algorithms/views.py
@@ -24,6 +24,7 @@
     ListView,
     UpdateView,
 )
+from django_filters.rest_framework import DjangoFilterBackend
 from guardian.core import ObjectPermissionChecker
 from guardian.mixins import (
     LoginRequiredMixin,
@@ -451,21 +452,24 @@ class AlgorithmImageViewSet(ReadOnlyModelViewSet):
     queryset = AlgorithmImage.objects.all()
     serializer_class = AlgorithmImageSerializer
     permission_classes = [DjangoObjectPermissions]
-    filter_backends = [ObjectPermissionsFilter]
+    filter_backends = [DjangoFilterBackend, ObjectPermissionsFilter]
+    filterset_fields = ["algorithm"]
 
 
 class JobViewSet(ReadOnlyModelViewSet):
     queryset = Job.objects.all()
     serializer_class = JobSerializer
     permission_classes = [DjangoObjectPermissions]
-    filter_backends = [ObjectPermissionsFilter]
+    filter_backends = [DjangoFilterBackend, ObjectPermissionsFilter]
+    filterset_fields = ["algorithm_image__algorithm", "image"]
 
 
 class ResultViewSet(ReadOnlyModelViewSet):
-    queryset = Result.objects.all()
+    queryset = Result.objects.all().prefetch_related("job")
     serializer_class = ResultSerializer
     permission_classes = [DjangoObjectPermissions]
-    filter_backends = [ObjectPermissionsFilter]
+    filter_backends = [DjangoFilterBackend, ObjectPermissionsFilter]
+    filterset_fields = ["job__algorithm_image__algorithm", "job__image"]
 
 
 class AlgorithmPermissionRequestCreate(
diff --git a/app/grandchallenge/reader_studies/views.py b/app/grandchallenge/reader_studies/views.py
--- a/app/grandchallenge/reader_studies/views.py
+++ b/app/grandchallenge/reader_studies/views.py
@@ -662,7 +662,7 @@ def _create_csv_response(self, data, headers, filename="export.csv"):
 class ReaderStudyViewSet(ExportCSVMixin, ReadOnlyModelViewSet):
     serializer_class = ReaderStudySerializer
     queryset = ReaderStudy.objects.all().prefetch_related(
-        "images", "questions"
+        "images", "questions__options"
     )
     permission_classes = [DjangoObjectOnlyPermissions]
     filter_backends = [ObjectPermissionsFilter]


Test patch: