From 8a59fc733c17ceac6356b944beb9aa917f775116 Mon Sep 17 00:00:00 2001 From: Marko Hauptvogel Date: Thu, 30 Oct 2025 13:33:34 +0100 Subject: [PATCH 1/5] Fix related object index Index related objects from 1 and not from 0, just like top-level objects. --- netbox/dcim/tests/test_views.py | 53 +++++++++++++++++++++++ netbox/netbox/views/generic/bulk_views.py | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index e1ba63ded..21d9e80aa 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -986,6 +986,59 @@ inventory-items: ii1 = InventoryItemTemplate.objects.first() self.assertEqual(ii1.name, 'Inventory Item 1') + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) + def test_import_error_numbering(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', + ) + + import_data = ''' +--- +manufacturer: Manufacturer 1 +model: TEST-2001 +slug: test-2001 +u_height: 1 +module-bays: + - name: Module Bay 1-1 + - name: Module Bay 1-2 +--- +- manufacturer: Manufacturer 1 + model: TEST-2002 + slug: test-2002 + u_height: 1 + module-bays: + - name: Module Bay 2-1 + - name: Module Bay 2-2 + - not_name: Module Bay 2-3 +- manufacturer: Manufacturer 1 + model: TEST-2003 + slug: test-2003 + u_height: 1 + module-bays: + - name: Module Bay 3-1 +''' + 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) + # TODO record index should be 2 + self.assertContains(response, "Record 3 module-bays[3].name: This field is required.") + def test_export_objects(self): url = reverse('dcim:devicetype_list') self.add_permissions('dcim.view_devicetype') diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 36c8ce1c4..228e79d7c 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -382,7 +382,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): for field_name, related_object_form in self.related_object_forms.items(): related_obj_pks = [] - for i, rel_obj_data in enumerate(model_form.data.get(field_name, list())): + for i, rel_obj_data in enumerate(model_form.data.get(field_name, list()), start=1): rel_obj_data = self.prep_related_object_data(obj, rel_obj_data) f = related_object_form(rel_obj_data) From 8452222761800ee6c1d9f2dc4db98795f16ecaaa Mon Sep 17 00:00:00 2001 From: Marko Hauptvogel Date: Thu, 30 Oct 2025 13:33:34 +0100 Subject: [PATCH 2/5] Fix record index for related objects Use the parent object index as record index, and its own index only on the field name. --- netbox/dcim/tests/test_views.py | 3 +-- netbox/netbox/views/generic/bulk_views.py | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 21d9e80aa..1643e381a 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1036,8 +1036,7 @@ module-bays: response = self.client.post(reverse('dcim:devicetype_bulk_import'), data=form_data, follow=True) self.assertHttpStatus(response, 200) - # TODO record index should be 2 - self.assertContains(response, "Record 3 module-bays[3].name: This field is required.") + self.assertContains(response, "Record 2 module-bays[3].name: This field is required.") def test_export_objects(self): url = reverse('dcim:devicetype_list') diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 228e79d7c..4b8bc61e9 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -368,7 +368,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): error_messages.append(f"Record {index} {prefix}{field_name}: {err}") return error_messages - def _save_object(self, model_form, request): + def _save_object(self, model_form, request, parent_idx): _action = 'Updated' if model_form.instance.pk else 'Created' # Save the primary object @@ -396,7 +396,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): else: # Replicate errors on the related object form to the import form for display and abort raise ValidationError( - self._compile_form_errors(f.errors, index=i, prefix=f'{field_name}[{i}]') + self._compile_form_errors(f.errors, index=parent_idx, prefix=f'{field_name}[{i}]') ) # Enforce object-level permissions on related objects @@ -481,7 +481,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): restrict_form_fields(model_form, request.user) if model_form.is_valid(): - obj = self._save_object(model_form, request) + obj = self._save_object(model_form, request, i) saved_objects.append(obj) else: # Raise model form errors From 78223cea03c93bb190042b280300cd5403b06b71 Mon Sep 17 00:00:00 2001 From: Marko Hauptvogel Date: Thu, 30 Oct 2025 13:33:34 +0100 Subject: [PATCH 3/5] Validate related object field is list 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. The error message is chosen to be similar in format and wording to the other existing validation errors. The used word "list" is quite universal, and conveys the wanted meaning in the context of python, json and yaml. --- netbox/dcim/tests/test_views.py | 36 +++++++++++++++++++++++ netbox/netbox/views/generic/bulk_views.py | 11 ++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 1643e381a..6636abaaa 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1038,6 +1038,42 @@ module-bays: self.assertHttpStatus(response, 200) self.assertContains(response, "Record 2 module-bays[3].name: This field is required.") + @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-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, "Record 1 console-ports: Must be a list.") + def test_export_objects(self): url = reverse('dcim:devicetype_list') self.add_permissions('dcim.view_devicetype') diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 4b8bc61e9..7dc8e4d2e 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -381,8 +381,17 @@ 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): + raise ValidationError( + self._compile_form_errors( + {field_name: [_("Must be a list.")]}, + index=parent_idx + ) + ) + related_obj_pks = [] - for i, rel_obj_data in enumerate(model_form.data.get(field_name, list()), start=1): + for i, rel_obj_data in enumerate(related_objects, start=1): rel_obj_data = self.prep_related_object_data(obj, rel_obj_data) f = related_object_form(rel_obj_data) From 1245a9f99db4b29359306567429ffe0ad38cba02 Mon Sep 17 00:00:00 2001 From: Marko Hauptvogel Date: Thu, 30 Oct 2025 13:33:34 +0100 Subject: [PATCH 4/5] Validate related object is dictionary 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. The word "dictionary" is used here, since it is python terminology, and is close enough to yaml's "mapping". While json calls them "objects", their key-value syntax should make it obvious what "dictionary" means here. --- netbox/dcim/tests/test_views.py | 37 +++++++++++++++++++++++ netbox/netbox/views/generic/bulk_views.py | 8 +++++ 2 files changed, 45 insertions(+) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 6636abaaa..7915203cd 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1074,6 +1074,43 @@ console-ports: {value} self.assertHttpStatus(response, 200) self.assertContains(response, "Record 1 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-4000 +slug: test-4000 +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, "Record 1 console-ports[1]: Must be a dictionary.") + def test_export_objects(self): url = reverse('dcim:devicetype_list') self.add_permissions('dcim.view_devicetype') diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 7dc8e4d2e..8d94273b1 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -392,6 +392,14 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): related_obj_pks = [] for i, rel_obj_data in enumerate(related_objects, start=1): + if not isinstance(rel_obj_data, dict): + raise ValidationError( + self._compile_form_errors( + {f'{field_name}[{i}]': [_("Must be a dictionary.")]}, + index=parent_idx, + ) + ) + rel_obj_data = self.prep_related_object_data(obj, rel_obj_data) f = related_object_form(rel_obj_data) From fbe76ac98aa2d58421dcb64cfe1a2898b4c50ad6 Mon Sep 17 00:00:00 2001 From: Marko Hauptvogel Date: Thu, 30 Oct 2025 14:08:15 +0100 Subject: [PATCH 5/5] Fix non-existent-id error message Change this one special case to also use the same communication channel (toast notification) and message format as all other validation errors. The error message is kept mostly the same, just the index prefix is removed. This allowed keeping and easily adjusting the existing localizations of it. --- netbox/netbox/views/generic/bulk_views.py | 10 +++++++--- netbox/translations/cs/LC_MESSAGES/django.po | 4 ++-- netbox/translations/da/LC_MESSAGES/django.po | 4 ++-- netbox/translations/de/LC_MESSAGES/django.po | 4 ++-- netbox/translations/en/LC_MESSAGES/django.po | 2 +- netbox/translations/es/LC_MESSAGES/django.po | 4 ++-- netbox/translations/fr/LC_MESSAGES/django.po | 4 ++-- netbox/translations/it/LC_MESSAGES/django.po | 4 ++-- netbox/translations/ja/LC_MESSAGES/django.po | 4 ++-- netbox/translations/nl/LC_MESSAGES/django.po | 4 ++-- netbox/translations/pl/LC_MESSAGES/django.po | 4 ++-- netbox/translations/pt/LC_MESSAGES/django.po | 4 ++-- netbox/translations/ru/LC_MESSAGES/django.po | 4 ++-- netbox/translations/tr/LC_MESSAGES/django.po | 4 ++-- netbox/translations/uk/LC_MESSAGES/django.po | 4 ++-- netbox/translations/zh/LC_MESSAGES/django.po | 4 ++-- 16 files changed, 36 insertions(+), 32 deletions(-) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 8d94273b1..7b7876532 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -323,7 +323,7 @@ class BulkCreateView(GetReturnURLMixin, BaseMultiObjectView): class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): """ - Import objects in bulk (CSV format). + Import objects in bulk (CSV/JSON/YAML format). Attributes: model_form: The form used to create each imported object @@ -456,8 +456,12 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): try: instance = prefetched_objects[object_id] except KeyError: - form.add_error('data', _("Row {i}: Object with ID {id} does not exist").format(i=i, id=object_id)) - raise ValidationError('') + raise ValidationError( + self._compile_form_errors( + {'id': [_("Object with ID {id} does not exist").format(id=object_id)]}, + index=i + ) + ) # Take a snapshot for change logging if instance.pk and hasattr(instance, 'snapshot'): diff --git a/netbox/translations/cs/LC_MESSAGES/django.po b/netbox/translations/cs/LC_MESSAGES/django.po index 18a542b78..b755550e8 100644 --- a/netbox/translations/cs/LC_MESSAGES/django.po +++ b/netbox/translations/cs/LC_MESSAGES/django.po @@ -12822,8 +12822,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Řádek {i}: Objekt s ID {id} neexistuje" +msgid "Object with ID {id} does not exist" +msgstr "Objekt s ID {id} neexistuje" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/da/LC_MESSAGES/django.po b/netbox/translations/da/LC_MESSAGES/django.po index 4bbe9c02c..52b507cd0 100644 --- a/netbox/translations/da/LC_MESSAGES/django.po +++ b/netbox/translations/da/LC_MESSAGES/django.po @@ -12857,8 +12857,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Række {i}: Objekt med ID {id} findes ikke" +msgid "Object with ID {id} does not exist" +msgstr "Objekt med ID {id} findes ikke" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/de/LC_MESSAGES/django.po b/netbox/translations/de/LC_MESSAGES/django.po index 6f7a9c873..1f6f4b642 100644 --- a/netbox/translations/de/LC_MESSAGES/django.po +++ b/netbox/translations/de/LC_MESSAGES/django.po @@ -13055,8 +13055,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Reihe {i}: Objekt mit ID {id} existiert nicht" +msgid "Object with ID {id} does not exist" +msgstr "Objekt mit ID {id} existiert nicht" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/en/LC_MESSAGES/django.po b/netbox/translations/en/LC_MESSAGES/django.po index 7104111c4..d45c9b533 100644 --- a/netbox/translations/en/LC_MESSAGES/django.po +++ b/netbox/translations/en/LC_MESSAGES/django.po @@ -12513,7 +12513,7 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" +msgid "Object with ID {id} does not exist" msgstr "" #: netbox/netbox/views/generic/bulk_views.py:525 diff --git a/netbox/translations/es/LC_MESSAGES/django.po b/netbox/translations/es/LC_MESSAGES/django.po index fd19f2b2a..9af4648ec 100644 --- a/netbox/translations/es/LC_MESSAGES/django.po +++ b/netbox/translations/es/LC_MESSAGES/django.po @@ -12999,8 +12999,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Fila {i}: Objeto con ID {id} no existe" +msgid "Object with ID {id} does not exist" +msgstr "Objeto con ID {id} no existe" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/fr/LC_MESSAGES/django.po b/netbox/translations/fr/LC_MESSAGES/django.po index 1487fa2b5..53166a755 100644 --- a/netbox/translations/fr/LC_MESSAGES/django.po +++ b/netbox/translations/fr/LC_MESSAGES/django.po @@ -13041,8 +13041,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Rangée {i}: Objet avec identifiant {id} n'existe pas" +msgid "Object with ID {id} does not exist" +msgstr "Objet avec identifiant {id} n'existe pas" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/it/LC_MESSAGES/django.po b/netbox/translations/it/LC_MESSAGES/django.po index e1132e620..9cd49edc0 100644 --- a/netbox/translations/it/LC_MESSAGES/django.po +++ b/netbox/translations/it/LC_MESSAGES/django.po @@ -13033,8 +13033,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Fila {i}: Oggetto con ID {id} non esiste" +msgid "Object with ID {id} does not exist" +msgstr "Oggetto con ID {id} non esiste" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/ja/LC_MESSAGES/django.po b/netbox/translations/ja/LC_MESSAGES/django.po index 4ffdf7838..76db9e261 100644 --- a/netbox/translations/ja/LC_MESSAGES/django.po +++ b/netbox/translations/ja/LC_MESSAGES/django.po @@ -12645,8 +12645,8 @@ msgstr "選択したエクスポートテンプレートをレンダリング中 #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "行 {i}: ID {id}のオブジェクトは存在しません" +msgid "Object with ID {id} does not exist" +msgstr "ID {id}のオブジェクトは存在しません" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/nl/LC_MESSAGES/django.po b/netbox/translations/nl/LC_MESSAGES/django.po index 0f7b297a4..2f820f94c 100644 --- a/netbox/translations/nl/LC_MESSAGES/django.po +++ b/netbox/translations/nl/LC_MESSAGES/django.po @@ -13000,8 +13000,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Rij {i}: Object met ID {id} bestaat niet" +msgid "Object with ID {id} does not exist" +msgstr "Object met ID {id} bestaat niet" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/pl/LC_MESSAGES/django.po b/netbox/translations/pl/LC_MESSAGES/django.po index 6f7ccee02..be5b12c07 100644 --- a/netbox/translations/pl/LC_MESSAGES/django.po +++ b/netbox/translations/pl/LC_MESSAGES/django.po @@ -12920,8 +12920,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Wiersz {i}: Obiekt z identyfikatorem {id} nie istnieje" +msgid "Object with ID {id} does not exist" +msgstr "Obiekt z identyfikatorem {id} nie istnieje" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/pt/LC_MESSAGES/django.po b/netbox/translations/pt/LC_MESSAGES/django.po index 0e9f8e32c..a96ea2695 100644 --- a/netbox/translations/pt/LC_MESSAGES/django.po +++ b/netbox/translations/pt/LC_MESSAGES/django.po @@ -12944,8 +12944,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Linha {i}: Objeto com ID {id} não existe" +msgid "Object with ID {id} does not exist" +msgstr "Objeto com ID {id} não existe" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/ru/LC_MESSAGES/django.po b/netbox/translations/ru/LC_MESSAGES/django.po index 00946d050..c1d6722f2 100644 --- a/netbox/translations/ru/LC_MESSAGES/django.po +++ b/netbox/translations/ru/LC_MESSAGES/django.po @@ -12939,8 +12939,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Ряд {i}: Объект с идентификатором {id} не существует" +msgid "Object with ID {id} does not exist" +msgstr "Объект с идентификатором {id} не существует" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/tr/LC_MESSAGES/django.po b/netbox/translations/tr/LC_MESSAGES/django.po index 24e98b629..254c994b3 100644 --- a/netbox/translations/tr/LC_MESSAGES/django.po +++ b/netbox/translations/tr/LC_MESSAGES/django.po @@ -12835,8 +12835,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Satır {i}: Kimliği olan nesne {id} mevcut değil" +msgid "Object with ID {id} does not exist" +msgstr "Kimliği olan nesne {id} mevcut değil" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/uk/LC_MESSAGES/django.po b/netbox/translations/uk/LC_MESSAGES/django.po index edd3d9d83..a3d8ecda8 100644 --- a/netbox/translations/uk/LC_MESSAGES/django.po +++ b/netbox/translations/uk/LC_MESSAGES/django.po @@ -12920,8 +12920,8 @@ msgstr "" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "Ряд {i}: Об'єкт з ідентифікатором {id} не існує" +msgid "Object with ID {id} does not exist" +msgstr "Об'єкт з ідентифікатором {id} не існує" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format diff --git a/netbox/translations/zh/LC_MESSAGES/django.po b/netbox/translations/zh/LC_MESSAGES/django.po index ce8622504..524612e27 100644 --- a/netbox/translations/zh/LC_MESSAGES/django.po +++ b/netbox/translations/zh/LC_MESSAGES/django.po @@ -12622,8 +12622,8 @@ msgstr "渲染所选导出模板时出错 ({template}): {error}" #: netbox/netbox/views/generic/bulk_views.py:442 #, python-brace-format -msgid "Row {i}: Object with ID {id} does not exist" -msgstr "第{i}行: ID为{id}的对象不存在" +msgid "Object with ID {id} does not exist" +msgstr "ID为{id}的对象不存在" #: netbox/netbox/views/generic/bulk_views.py:525 #, python-brace-format