diff --git a/app/grandchallenge/algorithms/admin.py b/app/grandchallenge/algorithms/admin.py index 044393a2d..03a32c6d6 100644 --- a/app/grandchallenge/algorithms/admin.py +++ b/app/grandchallenge/algorithms/admin.py @@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import Count, Sum from django.forms import ModelForm +from django.urls import reverse from django.utils.html import format_html from guardian.admin import GuardedModelAdmin @@ -52,12 +53,17 @@ class Meta: @admin.register(Algorithm) class AlgorithmAdmin(GuardedModelAdmin): - readonly_fields = ("algorithm_forge_json", "inputs", "outputs") + readonly_fields = ( + "algorithm_forge_json", + "default_interface_link", + "inputs", + "outputs", + ) list_display = ( "title", "created", "public", - "default_io", + "default_interface_link", "time_limit", "job_requires_gpu_type", "job_requires_memory_gb", @@ -72,6 +78,19 @@ class AlgorithmAdmin(GuardedModelAdmin): def container_count(self, obj): return obj.container_count + def default_interface_link(self, obj): + if obj.default_interface: + return format_html( + '{default_interface}', + link=reverse( + "admin:algorithms_algorithminterface_change", + kwargs={"object_id": obj.default_interface.pk}, + ), + default_interface=obj.default_interface, + ) + else: + return None + @staticmethod def algorithm_forge_json(obj): json_desc = get_forge_algorithm_template_context(algorithm=obj) @@ -79,11 +98,6 @@ def algorithm_forge_json(obj): "
{json_desc}", json_desc=json.dumps(json_desc, indent=2) ) - def default_io(self, obj): - return AlgorithmAlgorithmInterface.objects.get( - algorithm=obj, is_default=True - ) - def get_queryset(self, request): queryset = super().get_queryset(request) queryset = queryset.annotate( diff --git a/app/grandchallenge/algorithms/forms.py b/app/grandchallenge/algorithms/forms.py index badbba7dd..8923731fe 100644 --- a/app/grandchallenge/algorithms/forms.py +++ b/app/grandchallenge/algorithms/forms.py @@ -1407,7 +1407,7 @@ def __init__(self, *args, algorithm, **kwargs): super().__init__(*args, **kwargs) self._algorithm = algorithm - if self._algorithm.needs_default_interface: + if not self._algorithm.default_interface: self.fields["set_as_default"].initial = True def clean(self): diff --git a/app/grandchallenge/algorithms/models.py b/app/grandchallenge/algorithms/models.py index 3dfec1a17..bb98a22e0 100644 --- a/app/grandchallenge/algorithms/models.py +++ b/app/grandchallenge/algorithms/models.py @@ -504,9 +504,14 @@ def default_workstation(self): return w - @property - def needs_default_interface(self): - return not self.interfaces.exists() + @cached_property + def default_interface(self): + try: + return self.interfaces.get( + algorithmalgorithminterface__is_default=True + ) + except ObjectDoesNotExist: + return None def is_editor(self, user): return user.groups.filter(pk=self.editors_group.pk).exists() diff --git a/app/tests/algorithms_tests/test_models.py b/app/tests/algorithms_tests/test_models.py index 2de0cdeac..6c7d8028b 100644 --- a/app/tests/algorithms_tests/test_models.py +++ b/app/tests/algorithms_tests/test_models.py @@ -1497,3 +1497,16 @@ def test_algorithminterface_create(): io = AlgorithmInterface.objects.create(inputs=inputs, outputs=outputs) assert list(io.inputs.all()) == inputs assert list(io.outputs.all()) == outputs + + +@pytest.mark.django_db +def test_has_default_interface(): + alg1, alg2, alg3 = AlgorithmFactory.create_batch(3) + io1, io2 = AlgorithmInterfaceFactory.create_batch(2) + + alg1.interfaces.add(io1, through_defaults={"is_default": True}) + alg2.interfaces.add(io2) + + assert alg1.default_interface == io1 + assert not alg2.default_interface + assert not alg3.default_interface diff --git a/app/tests/algorithms_tests/test_views.py b/app/tests/algorithms_tests/test_views.py index 3643648c0..40798ccaf 100644 --- a/app/tests/algorithms_tests/test_views.py +++ b/app/tests/algorithms_tests/test_views.py @@ -2218,7 +2218,11 @@ def test_algorithm_interface_create(client): client=client, method=client.post, reverse_kwargs={"slug": alg.slug}, - data={"inputs": [ci_1.pk], "outputs": [ci_2.pk]}, + data={ + "inputs": [ci_1.pk], + "outputs": [ci_2.pk], + "set_as_default": True, + }, user=user, ) assert response.status_code == 302 @@ -2247,7 +2251,7 @@ def test_algorithm_interfaces_list_queryset(client): alg.interfaces.set([io1, io2]) alg2.interfaces.set([io3, io4]) - iots = AlgorithmAlgorithmInterface.objects.order_by("created").all() + iots = AlgorithmAlgorithmInterface.objects.order_by("id").all() VerificationFactory(user=user, is_verified=True)