Arthur 6 дней назад
Родитель
Сommit
ea2f1f6189
2 измененных файлов с 16 добавлено и 2 удалено
  1. 10 1
      netbox/extras/scripts.py
  2. 6 1
      netbox/extras/tests/test_views.py

+ 10 - 1
netbox/extras/scripts.py

@@ -723,6 +723,15 @@ def prepare_script_form(script_instance, data, files=None):
     """
     data = data.copy() if data is not None else {}
     for name, var in script_instance._get_vars().items():
-        if name not in data and (initial := var.field_attrs.get('initial')) is not None:
+        if name in data:
+            continue
+        if (initial := var.field_attrs.get('initial')) is None:
+            continue
+        if isinstance(initial, (list, tuple)) and hasattr(data, 'setlist'):
+            # Assigning a list to a QueryDict stores it as a single nested value, which a
+            # multi-select widget reads back as one bogus choice. Set the values individually
+            # so a MultiChoiceVar/MultiObjectVar default binds as it does for a plain dict.
+            data.setlist(name, list(initial))
+        else:
             data[name] = initial
     return script_instance.as_form(data=data, files=files)

+ 6 - 1
netbox/extras/tests/test_views.py

@@ -14,7 +14,7 @@ from core.models import Job, ObjectType
 from dcim.models import DeviceType, Manufacturer, Site
 from extras.choices import *
 from extras.models import *
-from extras.scripts import BooleanVar, IntegerVar, StringVar
+from extras.scripts import BooleanVar, IntegerVar, MultiChoiceVar, StringVar
 from extras.scripts import Script as PythonClass
 from users.models import Group, ObjectPermission, User
 from utilities.testing import TestCase, ViewTestCases
@@ -1294,6 +1294,7 @@ class ScriptDefaultBackfillTestCase(TestCase):
 
         label = StringVar(default='hello')
         flag = BooleanVar(default=True)
+        picks = MultiChoiceVar(choices=(('a', 'A'), ('b', 'B'), ('c', 'C')), default=['a', 'b'])
 
         def run(self, data, commit):
             return 'Complete'
@@ -1328,6 +1329,10 @@ class ScriptDefaultBackfillTestCase(TestCase):
         data = mock_enqueue.call_args.kwargs['data']
         self.assertEqual(data['label'], 'hello')
         self.assertIs(data['flag'], True)
+        # A multi-value default must be set on the QueryDict with setlist(): a plain
+        # assignment stores the list as one nested value, which the multi-select widget
+        # then rejects as a single invalid choice.
+        self.assertEqual(data['picks'], ['a', 'b'])
 
 
 class ScriptValidationErrorTestCase(TestCase):