瀏覽代碼

16073 set default custom fields on CSV import (#17152)

* 16073 set default custom fields on CSV import

* 16073 add test case

* Remove second for loop

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Arthur Hanson 1 年之前
父節點
當前提交
872af72b8e
共有 2 個文件被更改,包括 40 次插入1 次删除
  1. 26 0
      netbox/netbox/tests/test_import.py
  2. 14 1
      netbox/netbox/views/generic/bulk_views.py

+ 26 - 0
netbox/netbox/tests/test_import.py

@@ -2,6 +2,7 @@ from django.test import override_settings
 
 
 from core.models import ObjectType
 from core.models import ObjectType
 from dcim.models import *
 from dcim.models import *
+from extras.models import CustomField
 from netbox.choices import CSVDelimiterChoices, ImportFormatChoices
 from netbox.choices import CSVDelimiterChoices, ImportFormatChoices
 from users.models import ObjectPermission
 from users.models import ObjectPermission
 from utilities.testing import ModelViewTestCase, create_tags
 from utilities.testing import ModelViewTestCase, create_tags
@@ -116,3 +117,28 @@ class CSVImportTestCase(ModelViewTestCase):
         # Test POST with permission
         # Test POST with permission
         self.assertHttpStatus(self.client.post(self._get_url('import'), data), 200)
         self.assertHttpStatus(self.client.post(self._get_url('import'), data), 200)
         self.assertEqual(Region.objects.count(), 0)
         self.assertEqual(Region.objects.count(), 0)
+
+    @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
+    def test_custom_field_defaults(self):
+        self.add_permissions('dcim.add_region')
+        csv_data = [
+            'name,slug,description',
+            'Region 1,region-1,abc',
+        ]
+        data = {
+            'format': ImportFormatChoices.CSV,
+            'data': self._get_csv_data(csv_data),
+            'csv_delimiter': CSVDelimiterChoices.AUTO,
+        }
+
+        cf = CustomField.objects.create(
+            name='tcf',
+            type='text',
+            required=False,
+            default='def-cf-text'
+        )
+        cf.object_types.set([ObjectType.objects.get_for_model(self.model)])
+
+        self.assertHttpStatus(self.client.post(self._get_url('import'), data), 302)
+        region = Region.objects.get(slug='region-1')
+        self.assertEqual(region.cf['tcf'], 'def-cf-text')

+ 14 - 1
netbox/netbox/views/generic/bulk_views.py

@@ -4,6 +4,7 @@ from copy import deepcopy
 
 
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.contenttypes.fields import GenericRel
 from django.contrib.contenttypes.fields import GenericRel
+from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
 from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
 from django.db import transaction, IntegrityError
 from django.db import transaction, IntegrityError
 from django.db.models import ManyToManyField, ProtectedError, RestrictedError
 from django.db.models import ManyToManyField, ProtectedError, RestrictedError
@@ -17,7 +18,8 @@ from django.utils.translation import gettext as _
 from django_tables2.export import TableExport
 from django_tables2.export import TableExport
 
 
 from core.models import ObjectType
 from core.models import ObjectType
-from extras.models import ExportTemplate
+from extras.choices import CustomFieldUIEditableChoices
+from extras.models import CustomField, ExportTemplate
 from extras.signals import clear_events
 from extras.signals import clear_events
 from utilities.error_handlers import handle_protectederror
 from utilities.error_handlers import handle_protectederror
 from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
 from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
@@ -415,6 +417,17 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
                 if instance.pk and hasattr(instance, 'snapshot'):
                 if instance.pk and hasattr(instance, 'snapshot'):
                     instance.snapshot()
                     instance.snapshot()
 
 
+            else:
+                # For newly created objects, apply any default custom field values
+                custom_fields = CustomField.objects.filter(
+                    object_types=ContentType.objects.get_for_model(self.queryset.model),
+                    ui_editable=CustomFieldUIEditableChoices.YES
+                )
+                for cf in custom_fields:
+                    field_name = f'cf_{cf.name}'
+                    if field_name not in record:
+                        record[field_name] = cf.default
+
             # Instantiate the model form for the object
             # Instantiate the model form for the object
             model_form_kwargs = {
             model_form_kwargs = {
                 'data': record,
                 'data': record,