1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Fixes #11617: Check for invalid CSV headers during bulk import (#13826)

* Fixes #11617: Check for invalid CSV headers during bulk import

* Add test for CSV import header validation
This commit is contained in:
Jeremy Stretch
2023-09-20 14:40:27 -04:00
committed by GitHub
parent f5dd7d853a
commit ae4ea3443e
3 changed files with 43 additions and 10 deletions

View File

@ -17,6 +17,36 @@ class CSVImportTestCase(ModelViewTestCase):
def _get_csv_data(self, csv_data): def _get_csv_data(self, csv_data):
return '\n'.join(csv_data) return '\n'.join(csv_data)
def test_invalid_headers(self):
"""
Test that import form validation fails when an unknown CSV header is present.
"""
self.add_permissions('dcim.add_region')
csv_data = [
'name,slug,INVALIDHEADER',
'Region 1,region-1,abc',
'Region 2,region-2,def',
'Region 3,region-3,ghi',
]
data = {
'format': ImportFormatChoices.CSV,
'data': self._get_csv_data(csv_data),
'csv_delimiter': CSVDelimiterChoices.AUTO,
}
# Form validation should fail with invalid header present
self.assertHttpStatus(self.client.post(self._get_url('import'), data), 200)
self.assertEqual(Region.objects.count(), 0)
# Correct the CSV header name
csv_data[0] = 'name,slug,description'
data['data'] = self._get_csv_data(csv_data)
# Validation should succeed
self.assertHttpStatus(self.client.post(self._get_url('import'), data), 302)
self.assertEqual(Region.objects.count(), 3)
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
def test_valid_tags(self): def test_valid_tags(self):
csv_data = ( csv_data = (

View File

@ -129,6 +129,7 @@ class BulkImportForm(BootstrapMixin, SyncedDataMixin, forms.Form):
headers, records = parse_csv(reader) headers, records = parse_csv(reader)
# Set CSV headers for reference by the model form # Set CSV headers for reference by the model form
headers.pop('id', None)
self._csv_headers = headers self._csv_headers = headers
return records return records

View File

@ -70,22 +70,24 @@ class CSVModelForm(forms.ModelForm):
""" """
ModelForm used for the import of objects in CSV format. ModelForm used for the import of objects in CSV format.
""" """
def __init__(self, *args, headers=None, fields=None, **kwargs): def __init__(self, *args, headers=None, **kwargs):
headers = headers or {} self.headers = headers or {}
fields = fields or []
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# Modify the model form to accommodate any customized to_field_name properties # 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: if to_field is not None:
self.fields[field].to_field_name = to_field self.fields[field].to_field_name = to_field
# Omit any fields not specified (e.g. because the form is being used to def clean(self):
# updated rather than create objects) # Flag any invalid CSV headers
if fields: for header in self.headers:
for field in list(self.fields.keys()): if header not in self.fields:
if field not in fields: raise forms.ValidationError(
del self.fields[field] _("Unrecognized header: {name}").format(name=header)
)
return super().clean()
class FilterForm(BootstrapMixin, forms.Form): class FilterForm(BootstrapMixin, forms.Form):