Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get_first_or_create method for CIVs #3602

Merged
merged 4 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions app/grandchallenge/algorithms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,21 +666,21 @@ def retrieve_existing_civs(*, civ_data):
continue
elif civ.image:
try:
civ = ComponentInterfaceValue.objects.filter(
civs = ComponentInterfaceValue.objects.filter(
interface__slug=civ.interface_slug, image=civ.image
).get()
existing_civs.append(civ)
).all()
existing_civs.extend(civs)
except ObjectDoesNotExist:
continue
elif civ.file_civ:
existing_civs.append(civ.file_civ)
else:
# values can be of different types, including None and False
try:
civ = ComponentInterfaceValue.objects.filter(
civs = ComponentInterfaceValue.objects.filter(
interface__slug=civ.interface_slug, value=civ.value
).get()
existing_civs.append(civ)
).all()
existing_civs.extend(civs)
except ObjectDoesNotExist:
continue

Expand Down
16 changes: 14 additions & 2 deletions app/grandchallenge/components/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,15 @@ def component_interface_value_path(instance, filename):
)


class ComponentInterfaceValueManager(models.Manager):

def get_first_or_create(self, **kwargs):
try:
return self.get_or_create(**kwargs)
except MultipleObjectsReturned:
return self.filter(**kwargs).first(), False


class ComponentInterfaceValue(models.Model):
"""Encapsulates the value of an interface at a certain point in the graph."""

Expand Down Expand Up @@ -1238,6 +1247,8 @@ class ComponentInterfaceValue(models.Model):

_user_upload_validated = False

objects = ComponentInterfaceValueManager()

@property
def title(self):
if self.value is not None:
Expand Down Expand Up @@ -2249,7 +2260,7 @@ def create_civ_for_value(
):
current_value = current_civ.value if current_civ else None

civ, created = ComponentInterfaceValue.objects.get_or_create(
civ, created = ComponentInterfaceValue.objects.get_first_or_create(
interface=ci, value=new_value
)

Expand Down Expand Up @@ -2290,9 +2301,10 @@ def create_civ_for_image( # noqa: C901
):
current_image = current_civ.image if current_civ else None
if image and current_image != image:
civ, created = ComponentInterfaceValue.objects.get_or_create(
civ, created = ComponentInterfaceValue.objects.get_first_or_create(
interface=ci, image=image
)

if created:
try:
civ.full_clean()
Expand Down
2 changes: 1 addition & 1 deletion app/grandchallenge/components/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ def add_image_to_object(
interface=interface, upload_session=upload_session
)

civ, created = ComponentInterfaceValue.objects.get_or_create(
civ, created = ComponentInterfaceValue.objects.get_first_or_create(
interface=interface, image=image
)

Expand Down
22 changes: 21 additions & 1 deletion app/tests/components_tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from unittest.mock import call

import pytest
from django.core.exceptions import ValidationError
from django.core.exceptions import MultipleObjectsReturned, ValidationError
from django.core.files.base import ContentFile
from django.utils import timezone
from panimg.models import MAXIMUM_SEGMENTS_LENGTH
Expand Down Expand Up @@ -1581,3 +1581,23 @@ def test_all_examples_present():
assert set(INTERFACE_TYPE_JSON_EXAMPLES.keys()) == set(
InterfaceKind.interface_type_json()
)


@pytest.mark.django_db
def test_component_interface_value_manager():
ci = ComponentInterfaceFactory(kind=InterfaceKindChoices.STRING)
civ1, civ2 = ComponentInterfaceValueFactory.create_batch(
2, interface=ci, value="Foo"
)

with pytest.raises(MultipleObjectsReturned):
ComponentInterfaceValue.objects.get_or_create(
interface=ci, value="Foo"
)

civ, created = ComponentInterfaceValue.objects.get_first_or_create(
interface=ci, value="Foo"
)

assert civ == civ1
assert not created