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 e1ba63ded67..21d9e80aa09 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -986,6 +986,59 @@ def test_import_objects(self): 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 36c8ce1c45d..228e79d7c0c 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -382,7 +382,7 @@ def _save_object(self, model_form, request): 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 21d9e80aa09..1643e381af1 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1036,8 +1036,7 @@ def test_import_error_numbering(self): 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 228e79d7c0c..4b8bc61e9d6 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -368,7 +368,7 @@ def _compile_form_errors(self, errors, index, prefix=None): 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 @@ def _save_object(self, model_form, request): 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 @@ def create_and_update_objects(self, form, request): 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 1643e381af1..6636abaaa5a 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1038,6 +1038,42 @@ def test_import_error_numbering(self): 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 4b8bc61e9d6..7dc8e4d2e6f 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -381,8 +381,17 @@ def _save_object(self, model_form, request, parent_idx): # 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 6636abaaa5a..7915203cda9 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1074,6 +1074,43 @@ def test_import_nolist(self): 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 7dc8e4d2e6f..8d94273b1f0 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -392,6 +392,14 @@ def _save_object(self, model_form, request, parent_idx): 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 8d94273b1f0..7b78765322b 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -323,7 +323,7 @@ def post(self, request): 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 @@ def create_and_update_objects(self, form, request): 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 18a542b780d..b755550e83b 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 4bbe9c02cac..52b507cd007 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 6f7a9c873c0..1f6f4b642dd 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 7104111c4de..d45c9b5337f 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 fd19f2b2ade..9af4648ecca 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 1487fa2b5de..53166a755da 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 e1132e62070..9cd49edc04c 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 4ffdf7838c9..76db9e26138 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 0f7b297a465..2f820f94ca9 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 6f7ccee0254..be5b12c07fa 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 0e9f8e32c3a..a96ea2695f2 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 00946d05025..c1d6722f2aa 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 24e98b629aa..254c994b36b 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 edd3d9d831d..a3d8ecda8b8 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 ce86225046e..524612e27e2 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