Skip to content

Commit fb43bd9

Browse files
authored
Remove use of auto_id without pattern for dynamically added sockets (#4473)
Replace use of auto_id with a dedicated form_id. Supplying `auto_id` changes django's behaviour of setting the id on form elements (it removed the default "id_" prefix) as explained in the [docs here](https://docs.djangoproject.com/en/5.2/ref/forms/api/#configuring-form-elements-html-id-attributes-and-label-tags). Because we only use the value to set the form id, we can use our own context variable for that. Also clean up some things: - Rename `DICOMUploadWidgetSuffixes` to `DICOM_UPLOAD_WIDGET_SUFFIXES` - Only check if socket exists for socket slugs that start with the right prefix (reduce calls to database when loading form fields for dynamically added sockets) Related to DIAGNijmegen/rse-roadmap#435
1 parent 31db2be commit fb43bd9

8 files changed

Lines changed: 37 additions & 28 deletions

File tree

app/grandchallenge/cases/widgets.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def compress(self, values):
211211
return non_empty_values[0]
212212

213213

214-
DICOMUploadWidgetSuffixes = ["dicom-image-name", "dicom-user-uploads"]
214+
DICOM_UPLOAD_WIDGET_SUFFIXES = ["dicom-image-name", "dicom-user-uploads"]
215215

216216

217217
class DICOMUploadWithName(NamedTuple):
@@ -230,8 +230,8 @@ class DICOMUploadWidget(MultiWidget):
230230

231231
def __init__(self, attrs=None):
232232
widgets = {
233-
DICOMUploadWidgetSuffixes[0]: DICOMImageSetNameInput(),
234-
DICOMUploadWidgetSuffixes[1]: DICOMUserUploadMultipleWidget(),
233+
DICOM_UPLOAD_WIDGET_SUFFIXES[0]: DICOMImageSetNameInput(),
234+
DICOM_UPLOAD_WIDGET_SUFFIXES[1]: DICOMUserUploadMultipleWidget(),
235235
}
236236
super().__init__(widgets, attrs)
237237

app/grandchallenge/components/forms.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from django.utils.text import format_lazy
1919

2020
from grandchallenge.algorithms.models import AlgorithmImage
21-
from grandchallenge.cases.widgets import DICOMUploadWidgetSuffixes
21+
from grandchallenge.cases.widgets import DICOM_UPLOAD_WIDGET_SUFFIXES
2222
from grandchallenge.components.backends.exceptions import (
2323
CIVNotEditableException,
2424
)
@@ -218,8 +218,11 @@ def __init__(self, *args, instance, base_obj, user, **kwargs): # noqa C901
218218
interface_slug = self.parse_slug(slug=slug)
219219

220220
if (
221-
ComponentInterface.objects.filter(slug=interface_slug).exists()
221+
interface_slug
222222
and slug not in self.fields.keys()
223+
and ComponentInterface.objects.filter(
224+
slug=interface_slug
225+
).exists()
223226
):
224227
interface = ComponentInterface.objects.filter(
225228
slug=interface_slug
@@ -257,8 +260,12 @@ def __init__(self, *args, instance, base_obj, user, **kwargs): # noqa C901
257260

258261
@staticmethod
259262
def parse_slug(*, slug):
263+
if not slug.startswith(INTERFACE_FORM_FIELD_PREFIX):
264+
return None
265+
260266
interface_slug = slug[len(INTERFACE_FORM_FIELD_PREFIX) :]
261-
for known_suffix in DICOMUploadWidgetSuffixes:
267+
268+
for known_suffix in DICOM_UPLOAD_WIDGET_SUFFIXES:
262269
if interface_slug.endswith(f"_{known_suffix}"):
263270
base_slug = interface_slug[: -len(f"_{known_suffix}")]
264271
return base_slug
@@ -332,10 +339,12 @@ def __init__(
332339
interface,
333340
base_obj,
334341
user,
342+
form_id,
335343
htmx_url,
336344
**kwargs,
337345
):
338346
super().__init__(*args, **kwargs)
347+
self.id = form_id
339348
data = kwargs.get("data")
340349

341350
try:
@@ -365,7 +374,7 @@ def __init__(
365374
"hx-get": htmx_url,
366375
"hx-trigger": "interfaceSelected",
367376
"disabled": selected_interface is not None,
368-
"hx-target": f"#form-{kwargs['auto_id']}",
377+
"hx-target": f"#form-{form_id}",
369378
"hx-swap": "outerHTML",
370379
"hx-include": "this",
371380
}
@@ -386,7 +395,7 @@ def __init__(
386395
widget_kwargs["url"] = (
387396
"components:component-interface-autocomplete"
388397
)
389-
interface_field_name = f"interface-{kwargs['auto_id']}"
398+
interface_field_name = f"interface-{form_id}"
390399
widget_kwargs["forward"] = [interface_field_name]
391400
widget_kwargs["attrs"] = attrs
392401

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{% load crispy_forms_tags %}
2-
<form class="extra-interface-form border rounded p-2 my-2" id="form-{{ form.auto_id }}">
3-
{% csrf_token %}
4-
{{ form|crispy }}
2+
3+
<form class="extra-interface-form border rounded p-2 my-2" id="form-{{ form.id }}">
4+
{% csrf_token %}
5+
{{ form|crispy }}
56
<button type="button" class="btn btn-danger remove-form">Remove</button>
67
</form>

app/grandchallenge/components/views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ def get_form_kwargs(self):
195195
kwargs.update(
196196
{
197197
"user": self.request.user,
198-
"auto_id": f"id-{uuid.uuid4()}",
199198
"base_obj": self.base_object,
200199
"instance": instance,
201200
}
@@ -269,7 +268,7 @@ def get_form_kwargs(self):
269268
"base_obj": self.base_object,
270269
"interface": self.request.GET.get("interface"),
271270
"user": self.request.user,
272-
"auto_id": f"id-{uuid.uuid4()}",
271+
"form_id": uuid.uuid4(),
273272
"htmx_url": self.get_htmx_url(),
274273
}
275274

app/tests/cases_tests/test_forms.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from django.test import Client
33

44
from grandchallenge.cases.models import RawImageUploadSession
5-
from grandchallenge.cases.widgets import DICOMUploadWidgetSuffixes
5+
from grandchallenge.cases.widgets import DICOM_UPLOAD_WIDGET_SUFFIXES
66
from grandchallenge.components.form_fields import INTERFACE_FORM_FIELD_PREFIX
77
from grandchallenge.components.forms import MultipleCIVForm
88
from grandchallenge.components.models import ComponentInterface
@@ -82,8 +82,8 @@ def test_upload_some_images(
8282
"slug",
8383
[
8484
f"{INTERFACE_FORM_FIELD_PREFIX}foo-bar",
85-
f"{INTERFACE_FORM_FIELD_PREFIX}foo-bar_{DICOMUploadWidgetSuffixes[0]}",
86-
f"{INTERFACE_FORM_FIELD_PREFIX}foo-bar_{DICOMUploadWidgetSuffixes[1]}",
85+
f"{INTERFACE_FORM_FIELD_PREFIX}foo-bar_{DICOM_UPLOAD_WIDGET_SUFFIXES[0]}",
86+
f"{INTERFACE_FORM_FIELD_PREFIX}foo-bar_{DICOM_UPLOAD_WIDGET_SUFFIXES[1]}",
8787
],
8888
)
8989
@pytest.mark.django_db

app/tests/cases_tests/test_widget.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from guardian.shortcuts import assign_perm
77

88
from grandchallenge.cases.widgets import (
9+
DICOM_UPLOAD_WIDGET_SUFFIXES,
910
DICOMUploadField,
10-
DICOMUploadWidgetSuffixes,
1111
DICOMUploadWithName,
1212
FlexibleImageField,
1313
)
@@ -222,10 +222,10 @@ def test_dicom_upload_field_validation():
222222
)
223223
parsed_value_for_upload_from_user = field.widget.value_from_datadict(
224224
data={
225-
f"{prefixed_interface_slug}_{DICOMUploadWidgetSuffixes[1]}": [
225+
f"{prefixed_interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[1]}": [
226226
str(upload1.pk)
227227
],
228-
f"{prefixed_interface_slug}_{DICOMUploadWidgetSuffixes[0]}": "test_image",
228+
f"{prefixed_interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[0]}": "test_image",
229229
},
230230
name=f"{prefixed_interface_slug}",
231231
files={},
@@ -246,10 +246,10 @@ def test_dicom_upload_field_validation():
246246
)
247247
parsed_value_from_upload_from_other_user = field.widget.value_from_datadict(
248248
data={
249-
f"{prefixed_interface_slug}_{DICOMUploadWidgetSuffixes[1]}": [
249+
f"{prefixed_interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[1]}": [
250250
str(upload2.pk)
251251
],
252-
f"{prefixed_interface_slug}_{DICOMUploadWidgetSuffixes[0]}": "test_image_2",
252+
f"{prefixed_interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[0]}": "test_image_2",
253253
},
254254
name=f"{prefixed_interface_slug}",
255255
files={},

app/tests/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from grandchallenge.algorithms.models import Job
1515
from grandchallenge.cases.widgets import (
16-
DICOMUploadWidgetSuffixes,
16+
DICOM_UPLOAD_WIDGET_SUFFIXES,
1717
ImageWidgetChoices,
1818
)
1919
from grandchallenge.components.backends import docker_client
@@ -516,10 +516,10 @@ def get_interface_form_data(
516516
ci = ComponentInterface.objects.get(slug=interface_slug)
517517
if ci.is_dicom_image_kind:
518518
form_data = {
519-
f"{INTERFACE_FORM_FIELD_PREFIX}{interface_slug}_{DICOMUploadWidgetSuffixes[0]}": data[
519+
f"{INTERFACE_FORM_FIELD_PREFIX}{interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[0]}": data[
520520
0
521521
],
522-
f"{INTERFACE_FORM_FIELD_PREFIX}{interface_slug}_{DICOMUploadWidgetSuffixes[1]}": data[
522+
f"{INTERFACE_FORM_FIELD_PREFIX}{interface_slug}_{DICOM_UPLOAD_WIDGET_SUFFIXES[1]}": data[
523523
1
524524
],
525525
}

app/tests/reader_studies_tests/test_forms.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,7 +1620,7 @@ def test_display_set_add_interface_form():
16201620
interface=None,
16211621
user=user,
16221622
htmx_url="foo",
1623-
auto_id="1",
1623+
form_id="1",
16241624
)
16251625
assert sorted(form.fields.keys()) == ["interface-1"]
16261626

@@ -1630,7 +1630,7 @@ def test_display_set_add_interface_form():
16301630
interface=ci_file.pk,
16311631
user=user,
16321632
htmx_url="foo",
1633-
auto_id="1",
1633+
form_id="1",
16341634
)
16351635
assert sorted(form.fields.keys()) == [
16361636
f"{INTERFACE_FORM_FIELD_PREFIX}{ci_file.slug}",
@@ -1647,7 +1647,7 @@ def test_display_set_add_interface_form():
16471647
interface=ci_value.pk,
16481648
user=user,
16491649
htmx_url="foo",
1650-
auto_id="1",
1650+
form_id="1",
16511651
)
16521652
assert sorted(form.fields.keys()) == [
16531653
f"{INTERFACE_FORM_FIELD_PREFIX}{ci_value.slug}",
@@ -1664,7 +1664,7 @@ def test_display_set_add_interface_form():
16641664
interface=ci_image.pk,
16651665
user=user,
16661666
htmx_url="foo",
1667-
auto_id="1",
1667+
form_id="1",
16681668
)
16691669
assert sorted(form.fields.keys()) == [
16701670
f"{INTERFACE_FORM_FIELD_PREFIX}{ci_image.slug}",

0 commit comments

Comments
 (0)