Fix hard related object not dict error

Elements of the "related objects list" are passed to the
`prep_related_object_data` function before any validation takes place,
with the potential of failing with a hard error. Similar to the "related
objects not list" case explicitly validate the elements general type,
and raise a normal validation error if it isn't a dictionary.
This commit is contained in:
Marko Hauptvogel 2025-08-22 09:53:51 +02:00
parent bb8f5ee12f
commit 16e284f03a
2 changed files with 41 additions and 0 deletions

View File

@ -1018,6 +1018,43 @@ console-ports: {value}
self.assertHttpStatus(response, 200) self.assertHttpStatus(response, 200)
self.assertContains(response, "console-ports: Must be a list.") self.assertContains(response, "console-ports: Must be a list.")
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
def test_import_nodict(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"', '["My other console port"]'):
with self.subTest(value=value):
import_data = f'''
manufacturer: Manufacturer 1
model: TEST-3000
slug: test-3000
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[0]: Must be a dictionary.")
def test_export_objects(self): def test_export_objects(self):
url = reverse('dcim:devicetype_list') url = reverse('dcim:devicetype_list')
self.add_permissions('dcim.view_devicetype') self.add_permissions('dcim.view_devicetype')

View File

@ -371,6 +371,10 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
related_obj_pks = [] related_obj_pks = []
for i, rel_obj_data in related_objects: for i, rel_obj_data in related_objects:
if not isinstance(rel_obj_data, dict): # TODO isinstance(MutableMapping)?
import_form.add_error(None, f"{field_name}[{i}]: {_('Must be a dictionary.')}")
raise AbortTransaction()
rel_obj_data = self.prep_related_object_data(obj, rel_obj_data) rel_obj_data = self.prep_related_object_data(obj, rel_obj_data)
f = related_object_form(rel_obj_data) f = related_object_form(rel_obj_data)