Fixes #21064: Ensures that extra choices preserve nested colons

This commit is contained in:
Jason Novinger
2026-01-05 14:42:20 -06:00
committed by Jeremy Stretch
parent 4d90d559be
commit 5a64cb712d
2 changed files with 33 additions and 7 deletions

View File

@@ -189,22 +189,22 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
# if standardize these, we can simplify this code
# Convert extra_choices Array Field from model to CharField for form
if 'extra_choices' in self.initial and self.initial['extra_choices']:
extra_choices = self.initial['extra_choices']
if extra_choices := self.initial.get('extra_choices', None):
if isinstance(extra_choices, str):
extra_choices = [extra_choices]
choices = ""
choices = []
for choice in extra_choices:
# Setup choices in Add Another use case
if isinstance(choice, str):
choice_str = ":".join(choice.replace("'", "").replace(" ", "")[1:-1].split(","))
choices += choice_str + "\n"
choices.append(choice_str)
# Setup choices in Edit use case
elif isinstance(choice, list):
choice_str = ":".join(choice)
choices += choice_str + "\n"
value = choice[0].replace(':', '\\:')
label = choice[1].replace(':', '\\:')
choices.append(f'{value}:{label}')
self.initial['extra_choices'] = choices
self.initial['extra_choices'] = '\n'.join(choices)
def clean_extra_choices(self):
data = []

View File

@@ -5,6 +5,7 @@ from dcim.forms import SiteForm
from dcim.models import Site
from extras.choices import CustomFieldTypeChoices
from extras.forms import SavedFilterForm
from extras.forms.model_forms import CustomFieldChoiceSetForm
from extras.models import CustomField, CustomFieldChoiceSet
@@ -90,6 +91,31 @@ class CustomFieldModelFormTest(TestCase):
self.assertIsNone(instance.custom_field_data[field_type])
class CustomFieldChoiceSetFormTest(TestCase):
def test_escaped_colons_preserved_on_edit(self):
choice_set = CustomFieldChoiceSet.objects.create(
name='Test Choice Set',
extra_choices=[['foo:bar', 'label'], ['value', 'label:with:colons']]
)
form = CustomFieldChoiceSetForm(instance=choice_set)
initial_choices = form.initial['extra_choices']
# colons are re-escaped
self.assertEqual(initial_choices, 'foo\\:bar:label\nvalue:label\\:with\\:colons')
form = CustomFieldChoiceSetForm(
{'name': choice_set.name, 'extra_choices': initial_choices},
instance=choice_set
)
self.assertTrue(form.is_valid())
updated = form.save()
# cleaned extra choices are correct, which does actually mean a list of tuples
self.assertEqual(updated.extra_choices, [('foo:bar', 'label'), ('value', 'label:with:colons')])
class SavedFilterFormTest(TestCase):
def test_basic_submit(self):