From 0615d368f2b3d0077a6f335d90adcb063414ad3c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 24 Sep 2019 16:51:59 -0400 Subject: [PATCH] Force validation of individual objects within a MultiObjectField --- netbox/dcim/forms.py | 21 ++++++++++----------- netbox/utilities/forms.py | 8 ++++++++ netbox/utilities/views.py | 9 +++++++-- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 9f465414d..6c145e9fa 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -848,7 +848,7 @@ class ConsolePortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = ConsolePortTemplate fields = [ - 'device_type', 'name', + 'name', ] @@ -857,7 +857,7 @@ class ConsoleServerPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = ConsoleServerPortTemplate fields = [ - 'device_type', 'name', + 'name', ] @@ -866,7 +866,7 @@ class PowerPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = PowerPortTemplate fields = [ - 'device_type', 'name', 'maximum_draw', 'allocated_draw', + 'name', 'maximum_draw', 'allocated_draw', ] @@ -880,7 +880,7 @@ class PowerOutletTemplateImportForm(ComponentTemplateImportForm): class Meta: model = PowerOutletTemplate fields = [ - 'device_type', 'name', 'power_port', 'feed_leg', + 'name', 'power_port', 'feed_leg', ] @@ -889,7 +889,7 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm): class Meta: model = InterfaceTemplate fields = [ - 'device_type', 'name', 'type', 'mgmt_only', + 'name', 'type', 'mgmt_only', ] @@ -903,7 +903,7 @@ class FrontPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = FrontPortTemplate fields = [ - 'device_type', 'name', 'type', 'rear_port', 'rear_port_position', + 'name', 'type', 'rear_port', 'rear_port_position', ] @@ -912,7 +912,7 @@ class RearPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = RearPortTemplate fields = [ - 'device_type', 'name', 'type', 'positions', + 'name', 'type', 'positions', ] @@ -966,12 +966,11 @@ class DeviceTypeImportForm(BootstrapMixin, forms.ModelForm): for field_name, field in self.fields.items(): if isinstance(field, MultiObjectField): for data in self.cleaned_data[field_name]: - data.update({ - 'device_type': instance.pk - }) form = field.form(data) if form.is_valid(): - form.save() + component = form.save(commit=False) + component.device_type = instance + component.save() return instance diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index dae9abda3..10390ca5e 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -570,6 +570,14 @@ class MultiObjectField(forms.Field): if value is None: return list() + for i, obj_data in enumerate(value, start=1): + form = self.form(obj_data) + if not form.is_valid(): + errors = [ + "Object {} {}: {}".format(i, field, errors) for field, errors in form.errors.items() + ] + raise forms.ValidationError(errors) + return value diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index b5406e145..fe39263b1 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -443,9 +443,14 @@ class ObjectImportView(GetReturnURLMixin, View): return redirect(self.get_return_url(request, obj)) else: + # Replicate model form errors for display - for field, err in model_form.errors.items(): - form.add_error(None, "{}: {}".format(field, err)) + for field, errors in model_form.errors.items(): + for err in errors: + if field == '__all__': + form.add_error(None, err) + else: + form.add_error(None, "{}: {}".format(field, err)) return render(request, self.template_name, { 'form': form,