diff --git a/netbox/utilities/forms/bulk_import.py b/netbox/utilities/forms/bulk_import.py index 63cec2ba2..57362d3dd 100644 --- a/netbox/utilities/forms/bulk_import.py +++ b/netbox/utilities/forms/bulk_import.py @@ -129,6 +129,7 @@ class BulkImportForm(BootstrapMixin, SyncedDataMixin, forms.Form): headers, records = parse_csv(reader) # Set CSV headers for reference by the model form + headers.pop('id', None) self._csv_headers = headers return records diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py index 04d956a49..54c9e41cb 100644 --- a/netbox/utilities/forms/forms.py +++ b/netbox/utilities/forms/forms.py @@ -70,22 +70,24 @@ class CSVModelForm(forms.ModelForm): """ ModelForm used for the import of objects in CSV format. """ - def __init__(self, *args, headers=None, fields=None, **kwargs): - headers = headers or {} - fields = fields or [] + def __init__(self, *args, headers=None, **kwargs): + self.headers = headers or {} super().__init__(*args, **kwargs) # Modify the model form to accommodate any customized to_field_name properties - for field, to_field in headers.items(): + for field, to_field in self.headers.items(): if to_field is not None: self.fields[field].to_field_name = to_field - # Omit any fields not specified (e.g. because the form is being used to - # updated rather than create objects) - if fields: - for field in list(self.fields.keys()): - if field not in fields: - del self.fields[field] + def clean(self): + # Flag any invalid CSV headers + for header in self.headers: + if header not in self.fields: + raise forms.ValidationError( + _("Unrecognized header: {name}").format(name=header) + ) + + return super().clean() class FilterForm(BootstrapMixin, forms.Form):