From 218f8e6c844ede06befb3017deded5c90200a6c0 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Wed, 14 Aug 2024 15:34:17 +0700 Subject: [PATCH 1/3] 16073 set default custom fields on CSV import --- netbox/netbox/views/generic/bulk_views.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index bc6ace885e4..73d808c36df 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -4,6 +4,7 @@ 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_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,20 @@ def create_and_update_objects(self, form, request): if instance.pk and hasattr(instance, 'snapshot'): instance.snapshot() + else: + # for newly created objects we need to add in the default custom-field + # values as the form is not posted back so the inital values don't have + # an effect. + custom_fields = CustomField.objects.filter( + object_types=ContentType.objects.get_for_model(self.queryset.model), + ui_editable=CustomFieldUIEditableChoices.YES + ) + append_fields = [cf for cf in custom_fields if f'cf_{cf.name}' not in record] + + for cf in append_fields: + field_name = f'cf_{cf.name}' + record[field_name] = cf.default + # Instantiate the model form for the object model_form_kwargs = { 'data': record, From 45ca3282dfbda42e3b4d0dfd75a31d2e1bc57de7 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Wed, 14 Aug 2024 18:06:54 +0700 Subject: [PATCH 2/3] 16073 add test case --- netbox/netbox/tests/test_import.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/netbox/netbox/tests/test_import.py b/netbox/netbox/tests/test_import.py index f382d011201..03690029c24 100644 --- a/netbox/netbox/tests/test_import.py +++ b/netbox/netbox/tests/test_import.py @@ -2,6 +2,7 @@ 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 @@ def test_invalid_tags(self): # 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') From 318cf5eb60e3a35b303462ef018b38d7ab5cd6c6 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 14 Aug 2024 08:03:55 -0400 Subject: [PATCH 3/3] Remove second for loop --- netbox/netbox/views/generic/bulk_views.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 73d808c36df..bdc9a7152a5 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -418,18 +418,15 @@ def create_and_update_objects(self, form, request): instance.snapshot() else: - # for newly created objects we need to add in the default custom-field - # values as the form is not posted back so the inital values don't have - # an effect. + # 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 ) - append_fields = [cf for cf in custom_fields if f'cf_{cf.name}' not in record] - - for cf in append_fields: + for cf in custom_fields: field_name = f'cf_{cf.name}' - record[field_name] = cf.default + if field_name not in record: + record[field_name] = cf.default # Instantiate the model form for the object model_form_kwargs = {