From 81024af0248c2cc3b1ac45bf80c8988f0f12f07e Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 29 Aug 2023 23:21:18 +0530 Subject: [PATCH] adds csv delimiter on the form --- netbox/templates/generic/bulk_import.html | 1 + netbox/utilities/choices.py | 14 +++++++++++ netbox/utilities/forms/bulk_import.py | 29 +++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/netbox/templates/generic/bulk_import.html b/netbox/templates/generic/bulk_import.html index 4396585b2..a8cbac5f6 100644 --- a/netbox/templates/generic/bulk_import.html +++ b/netbox/templates/generic/bulk_import.html @@ -44,6 +44,7 @@ Context: {% render_field form.data %} {% render_field form.format %} + {% render_field form.csv_delimiter %}
diff --git a/netbox/utilities/choices.py b/netbox/utilities/choices.py index 5ad05b989..5fd427059 100644 --- a/netbox/utilities/choices.py +++ b/netbox/utilities/choices.py @@ -227,3 +227,17 @@ class ImportFormatChoices(ChoiceSet): (JSON, 'JSON'), (YAML, 'YAML'), ] + + +class CSVDelimiterChoices(ChoiceSet): + AUTO = 'auto' + COMMA = ',' + SEMICOLON = ';' + TAB = '\t' + + CHOICES = [ + (AUTO, 'Auto-detect'), + (COMMA, 'Comma'), + (SEMICOLON, 'Semicolon'), + (TAB, 'Tab'), + ] diff --git a/netbox/utilities/forms/bulk_import.py b/netbox/utilities/forms/bulk_import.py index efdef0c7d..0a63c550f 100644 --- a/netbox/utilities/forms/bulk_import.py +++ b/netbox/utilities/forms/bulk_import.py @@ -7,7 +7,7 @@ from django import forms from django.utils.translation import gettext as _ from core.forms.mixins import SyncedDataMixin -from utilities.choices import ImportFormatChoices +from utilities.choices import CSVDelimiterChoices, ImportFormatChoices from utilities.forms.utils import parse_csv from .mixins import BootstrapMixin from ..choices import ImportMethodChoices @@ -31,6 +31,13 @@ class BulkImportForm(BootstrapMixin, SyncedDataMixin, forms.Form): choices=ImportFormatChoices, initial=ImportFormatChoices.AUTO ) + csv_delimiter = forms.ChoiceField( + choices=CSVDelimiterChoices, + initial=CSVDelimiterChoices.AUTO, + label="CSV Delimiter", + help_text=_("The character which delimits CSV fields. Applies only to CSV format."), + required=False + ) data_field = 'data' @@ -91,13 +98,21 @@ class BulkImportForm(BootstrapMixin, SyncedDataMixin, forms.Form): Clean CSV-formatted data. The first row will be treated as column headers. """ - # Determine the CSV dialect - try: - # This uses a rough heuristic to detect the CSV dialect. If the data is malformed, we'll fall back to - # the default Excel dialect. - dialect = csv.Sniffer().sniff(data.strip(), delimiters=',; ') - except csv.Error: + if self.cleaned_data['csv_delimiter'] == CSVDelimiterChoices.AUTO: + # Determine the CSV dialect + try: + # This uses a rough heuristic to detect the CSV dialect. If the data is malformed, we'll fall back to + # the default Excel dialect. + dialect = csv.Sniffer().sniff( + data.strip(), delimiters=''.join( + [CSVDelimiterChoices.COMMA, CSVDelimiterChoices.SEMICOLON, CSVDelimiterChoices.TAB] + ) + ) + except csv.Error: + dialect = csv.excel + else: dialect = csv.excel + dialect.delimiter = self.cleaned_data['csv_delimiter'] stream = StringIO(data.strip()) reader = csv.reader(stream, dialect=dialect)