diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 2bb4dea6d..afd1919ec 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -493,6 +493,18 @@ class SiteTestCase(APIViewTestCases.APIViewTestCase): # A non-list body is described by its type, so that the client can see what was sent self.assertEqual(response.data['detail'], 'Expected a list of objects, but got dict.') + # A multipart body reaches the bulk action as a QueryDict, which must be reported as the + # dict the client submitted rather than by that internal class name + response = self.client.patch( + self._get_list_url(), {'id': site.pk, 'description': 'x'}, format='multipart', **self.header + ) + + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data['detail'], 'Expected a list of objects, but got dict.') + + site.refresh_from_db() + self.assertEqual(site.description, '') + def test_bulk_write_objects_empty_body(self): """ Address a list endpoint with no body at all. An absent body reaches the bulk actions as an diff --git a/netbox/netbox/api/viewsets/mixins.py b/netbox/netbox/api/viewsets/mixins.py index 42b49f55f..094d65c18 100644 --- a/netbox/netbox/api/viewsets/mixins.py +++ b/netbox/netbox/api/viewsets/mixins.py @@ -93,16 +93,13 @@ def get_non_list_response(data): if isinstance(data, list): return None - # A request with no body at all arrives here as an empty dict, so reporting its type would tell - # the client only that it "got dict" -- unhelpful for what is the likeliest way to reach this - # point: a DELETE addressed to a list endpoint with nothing in the body. An explicitly submitted - # empty object is indistinguishable at this stage, and wants the same message anyway. if data is None or data == {} or data == '': detail = _('Expected a list of objects, but no data was submitted.') else: - detail = _('Expected a list of objects, but got {datatype}.').format( - datatype=type(data).__name__ - ) + # A multipart body arrives as a QueryDict rather than as a plain dict, so report any mapping + # by the type the client submitted rather than by the class which happens to carry it. + datatype = 'dict' if isinstance(data, dict) else type(data).__name__ + detail = _('Expected a list of objects, but got {datatype}.').format(datatype=datatype) return Response({'detail': detail}, status=status.HTTP_400_BAD_REQUEST)