Skip to content

Commit cd8590d

Browse files
committed
Add prep_related_object_list hook
Related objects are saved in the same order as they are defined in the input by the user. So related objects with a dependency on another need to be saved after the related object they depend on. Which means that when required, the order needs to be changed. The related object lists are not part of the actual form, and the individual related-object forms only cover the elements themselves. So while the re-order should be done at the form-level during the clean- step, there is no form covering the lists to use for that. Plus should all errors be reported with their original location/index and not with the fixed/resorted one, because these are not useful and even confusing for the user. So the sorting should be done as late as possible, ideally just before the save. This adds a new `prep_related_object_list` hook, which gets passed each list of related objects. This should only be used for modifications to the list (aka order). Any changes to the individual objects should still be done using the existing `prep_related_object_data` hook. The passed list is not the plain list, but an enumerated variant. This is needed to preserve the original index of the elements independently from the actual (possibly changed) order the list, so any later detected errors (for example by the elements form validation) can accurately be reported back to the user.
1 parent deb6b1e commit cd8590d

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

netbox/netbox/views/generic/bulk_views.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.db import IntegrityError, router, transaction
1010
from django.db.models import ManyToManyField, ProtectedError, RestrictedError
1111
from django.db.models.fields.reverse_related import ManyToManyRel
12-
from django.forms import ModelMultipleChoiceField, MultipleHiddenInput
12+
from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, ValidationError
1313
from django.http import HttpResponse
1414
from django.shortcuts import get_object_or_404, redirect, render
1515
from django.urls import reverse
@@ -328,6 +328,13 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
328328
def get_required_permission(self):
329329
return get_permission_for_model(self.queryset.model, 'add')
330330

331+
def prep_related_object_list(self, field_name, enumerated_list):
332+
"""
333+
Hook to modify the enumerated list of related objects before it's passed to the related object form (for
334+
example, to change the order).
335+
"""
336+
pass # TODO keep in-place only, or return modified list?
337+
331338
def prep_related_object_data(self, parent, data):
332339
"""
333340
Hook to modify the data for related objects before it's passed to the related object form (for example, to
@@ -369,6 +376,13 @@ def _save_object(self, import_form, model_form, request):
369376
raise AbortTransaction()
370377
related_objects = list(enumerate(related_objects))
371378

379+
try:
380+
self.prep_related_object_list(field_name, related_objects)
381+
except ValidationError as e:
382+
for message in e.messages:
383+
import_form.add_error(None, f"{field_name}: {message}")
384+
raise AbortTransaction()
385+
372386
related_obj_pks = []
373387
for i, rel_obj_data in related_objects:
374388
if not isinstance(rel_obj_data, dict): # TODO isinstance(MutableMapping)?

0 commit comments

Comments
 (0)