diff --git a/netbox/netbox/tests/test_import.py b/netbox/netbox/tests/test_import.py index f382d0112..03690029c 100644 --- a/netbox/netbox/tests/test_import.py +++ b/netbox/netbox/tests/test_import.py @@ -2,6 +2,7 @@ from django.test import override_settings from core.models import ObjectType from dcim.models import * +from extras.models import CustomField from netbox.choices import CSVDelimiterChoices, ImportFormatChoices from users.models import ObjectPermission from utilities.testing import ModelViewTestCase, create_tags @@ -116,3 +117,28 @@ class CSVImportTestCase(ModelViewTestCase): # Test POST with permission self.assertHttpStatus(self.client.post(self._get_url('import'), data), 200) 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') diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index bc6ace885..bdc9a7152 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -4,6 +4,7 @@ from copy import deepcopy from django.contrib import messages from django.contrib.contenttypes.fields import GenericRel +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError from django.db import transaction, IntegrityError 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 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 utilities.error_handlers import handle_protectederror from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation @@ -415,6 +417,17 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): if instance.pk and hasattr(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 model_form_kwargs = { 'data': record,