Просмотр исходного кода

20645 CSVChoiceField use default if blank

Arthur 3 месяцев назад
Родитель
Сommit
90712fa865
2 измененных файлов с 54 добавлено и 1 удалено
  1. 21 1
      netbox/utilities/forms/fields/csv.py
  2. 33 0
      netbox/utilities/tests/test_forms.py

+ 21 - 1
netbox/utilities/forms/fields/csv.py

@@ -18,6 +18,20 @@ __all__ = (
 )
 
 
+class CSVSelectWidget(forms.Select):
+    """
+    Custom Select widget for CSV imports that treats blank values as omitted.
+    This allows model defaults to be applied when a CSV field is present but empty.
+    """
+    def value_omitted_from_data(self, data, files, name):
+        # Check if value is omitted using parent behavior
+        if super().value_omitted_from_data(data, files, name):
+            return True
+        # Treat blank/empty strings as omitted to allow model defaults
+        value = data.get(name)
+        return value == '' or value is None
+
+
 class CSVChoicesMixin:
     STATIC_CHOICES = True
 
@@ -29,8 +43,9 @@ class CSVChoicesMixin:
 class CSVChoiceField(CSVChoicesMixin, forms.ChoiceField):
     """
     A CSV field which accepts a single selection value.
+    Treats blank CSV values as omitted to allow model defaults.
     """
-    pass
+    widget = CSVSelectWidget
 
 
 class CSVMultipleChoiceField(CSVChoicesMixin, forms.MultipleChoiceField):
@@ -46,7 +61,12 @@ class CSVMultipleChoiceField(CSVChoicesMixin, forms.MultipleChoiceField):
 
 
 class CSVTypedChoiceField(forms.TypedChoiceField):
+    """
+    A CSV field for typed choice values.
+    Treats blank CSV values as omitted to allow model defaults.
+    """
     STATIC_CHOICES = True
+    widget = CSVSelectWidget
 
 
 class CSVModelChoiceField(forms.ModelChoiceField):

+ 33 - 0
netbox/utilities/tests/test_forms.py

@@ -4,6 +4,7 @@ from django.test import TestCase
 from dcim.models import Site
 from netbox.choices import ImportFormatChoices
 from utilities.forms.bulk_import import BulkImportForm
+from utilities.forms.fields.csv import CSVSelectWidget
 from utilities.forms.forms import BulkRenameForm
 from utilities.forms.utils import get_field_value, expand_alphanumeric_pattern, expand_ipaddress_pattern
 
@@ -448,3 +449,35 @@ class GetFieldValueTest(TestCase):
             get_field_value(form, 'site'),
             None
         )
+
+
+class CSVSelectWidgetTest(TestCase):
+    """
+    Validate that CSVSelectWidget treats blank values as omitted.
+    This allows model defaults to be applied when CSV fields are present but empty.
+    Related to issue #20645.
+    """
+
+    def test_blank_value_treated_as_omitted(self):
+        """Test that blank string values are treated as omitted"""
+        widget = CSVSelectWidget()
+        data = {'test_field': ''}
+        self.assertTrue(widget.value_omitted_from_data(data, {}, 'test_field'))
+
+    def test_none_value_treated_as_omitted(self):
+        """Test that None values are treated as omitted"""
+        widget = CSVSelectWidget()
+        data = {'test_field': None}
+        self.assertTrue(widget.value_omitted_from_data(data, {}, 'test_field'))
+
+    def test_missing_field_treated_as_omitted(self):
+        """Test that missing fields are treated as omitted"""
+        widget = CSVSelectWidget()
+        data = {}
+        self.assertTrue(widget.value_omitted_from_data(data, {}, 'test_field'))
+
+    def test_valid_value_not_omitted(self):
+        """Test that valid values are not treated as omitted"""
+        widget = CSVSelectWidget()
+        data = {'test_field': 'valid_value'}
+        self.assertFalse(widget.value_omitted_from_data(data, {}, 'test_field'))