Fix hard related objects not list error

The related object fields are not covered by the form, so don't pass
any validation before trying to iterate over them and accessing their
elements. Instead of allowing a hard technical error to be raised,
explicitly check that it is indeed a list, and raise a normal validation
error if not.
This commit is contained in:
Marko Hauptvogel 2025-08-22 09:53:51 +02:00
parent 6b3b4b3193
commit bb8f5ee12f
2 changed files with 43 additions and 1 deletions

View File

@ -982,6 +982,42 @@ inventory-items:
ii1 = InventoryItemTemplate.objects.first()
self.assertEqual(ii1.name, 'Inventory Item 1')
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
def test_import_nolist(self):
# Add all required permissions to the test user
self.add_permissions(
'dcim.view_devicetype',
'dcim.add_devicetype',
'dcim.add_consoleporttemplate',
'dcim.add_consoleserverporttemplate',
'dcim.add_powerporttemplate',
'dcim.add_poweroutlettemplate',
'dcim.add_interfacetemplate',
'dcim.add_frontporttemplate',
'dcim.add_rearporttemplate',
'dcim.add_modulebaytemplate',
'dcim.add_devicebaytemplate',
'dcim.add_inventoryitemtemplate',
)
for value in ('', 'null', '3', '"My console port"', '{name: "My other console port"}'):
with self.subTest(value=value):
import_data = f'''
manufacturer: Manufacturer 1
model: TEST-2000
slug: test-2000
u_height: 1
console-ports: {value}
'''
form_data = {
'data': import_data,
'format': 'yaml'
}
response = self.client.post(reverse('dcim:devicetype_bulk_import'), data=form_data, follow=True)
self.assertHttpStatus(response, 200)
self.assertContains(response, "console-ports: Must be a list.")
def test_export_objects(self):
url = reverse('dcim:devicetype_list')
self.add_permissions('dcim.view_devicetype')

View File

@ -363,8 +363,14 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
# Iterate through the related object forms (if any), validating and saving each instance.
for field_name, related_object_form in self.related_object_forms.items():
related_objects = model_form.data.get(field_name, list())
if not isinstance(related_objects, list): # TODO isinstance(Sequence)?
import_form.add_error(None, f"{field_name}: {_('Must be a list.')}")
raise AbortTransaction()
related_objects = list(enumerate(related_objects))
related_obj_pks = []
for i, rel_obj_data in enumerate(model_form.data.get(field_name, list())):
for i, rel_obj_data in related_objects:
rel_obj_data = self.prep_related_object_data(obj, rel_obj_data)
f = related_object_form(rel_obj_data)