mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-13 16:47:34 -06:00
* Closes #19739: Add a user preference for CSV delimiter in table exports * Pass custom delimiter when exporting entire table
This commit is contained in:
parent
a1cd81ff35
commit
90e8a61670
@ -44,3 +44,10 @@ CENSOR_TOKEN_CHANGED = '***CHANGED***'
|
||||
|
||||
# Placeholder text for empty tables
|
||||
EMPTY_TABLE_TEXT = 'No results found'
|
||||
|
||||
# CSV delimiters
|
||||
CSV_DELIMITERS = {
|
||||
'comma': ',',
|
||||
'semicolon': ';',
|
||||
'pipe': '|',
|
||||
}
|
||||
|
@ -72,6 +72,16 @@ PREFERENCES = {
|
||||
),
|
||||
description=_('The preferred syntax for displaying generic data within the UI')
|
||||
),
|
||||
'csv_delimiter': UserPreference(
|
||||
label=_('CSV delimiter'),
|
||||
choices=(
|
||||
('comma', 'Comma (,)'),
|
||||
('semicolon', 'Semicolon (;)'),
|
||||
('pipe', 'Pipe (|)'),
|
||||
),
|
||||
default='comma',
|
||||
description=_('The character used to separate fields in CSV data')
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext as _
|
||||
from django_tables2.export import TableExport
|
||||
from mptt.models import MPTTModel
|
||||
|
||||
from core.models import ObjectType
|
||||
@ -25,6 +24,7 @@ from extras.models import CustomField, ExportTemplate
|
||||
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename
|
||||
from utilities.error_handlers import handle_protectederror
|
||||
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
|
||||
from utilities.export import TableExport
|
||||
from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
|
||||
from utilities.forms.bulk_import import BulkImportForm
|
||||
from utilities.htmx import htmx_partial
|
||||
@ -77,7 +77,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
|
||||
return '---\n'.join(yaml_data)
|
||||
|
||||
def export_table(self, table, columns=None, filename=None):
|
||||
def export_table(self, table, columns=None, filename=None, delimiter=None):
|
||||
"""
|
||||
Export all table data in CSV format.
|
||||
|
||||
@ -86,6 +86,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
columns: A list of specific columns to include. If None, all columns will be exported.
|
||||
filename: The name of the file attachment sent to the client. If None, will be determined automatically
|
||||
from the queryset model name.
|
||||
delimiter: The character used to separate columns (a comma is used by default)
|
||||
"""
|
||||
exclude_columns = {'pk', 'actions'}
|
||||
if columns:
|
||||
@ -96,7 +97,8 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
exporter = TableExport(
|
||||
export_format=TableExport.CSV,
|
||||
table=table,
|
||||
exclude_columns=exclude_columns
|
||||
exclude_columns=exclude_columns,
|
||||
delimiter=delimiter,
|
||||
)
|
||||
return exporter.response(
|
||||
filename=filename or f'netbox_{self.queryset.model._meta.verbose_name_plural}.csv'
|
||||
@ -159,7 +161,8 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
if request.GET['export'] == 'table':
|
||||
table = self.get_table(self.queryset, request, has_table_actions)
|
||||
columns = [name for name, _ in table.selected_columns]
|
||||
return self.export_table(table, columns)
|
||||
delimiter = request.user.config.get('csv_delimiter')
|
||||
return self.export_table(table, columns, delimiter=delimiter)
|
||||
|
||||
# Render an ExportTemplate
|
||||
elif request.GET['export']:
|
||||
@ -176,7 +179,8 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
# Fall back to default table/YAML export
|
||||
else:
|
||||
table = self.get_table(self.queryset, request, has_table_actions)
|
||||
return self.export_table(table)
|
||||
delimiter = request.user.config.get('csv_delimiter')
|
||||
return self.export_table(table, delimiter=delimiter)
|
||||
|
||||
# Render the objects table
|
||||
table = self.get_table(self.queryset, request, has_table_actions)
|
||||
|
@ -62,7 +62,7 @@ class UserConfigForm(forms.ModelForm, metaclass=UserConfigFormMetaclass):
|
||||
'ui.tables.striping',
|
||||
name=_('User Interface')
|
||||
),
|
||||
FieldSet('data_format', name=_('Miscellaneous')),
|
||||
FieldSet('data_format', 'csv_delimiter', name=_('Miscellaneous')),
|
||||
)
|
||||
# List of clearable preferences
|
||||
pk = forms.MultipleChoiceField(
|
||||
|
26
netbox/utilities/export.py
Normal file
26
netbox/utilities/export.py
Normal file
@ -0,0 +1,26 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_tables2.export import TableExport as TableExport_
|
||||
|
||||
from netbox.constants import CSV_DELIMITERS
|
||||
|
||||
__all__ = (
|
||||
'TableExport',
|
||||
)
|
||||
|
||||
|
||||
class TableExport(TableExport_):
|
||||
"""
|
||||
A subclass of django-tables2's TableExport class which allows us to specify a delimiting
|
||||
characters for CSV exports.
|
||||
"""
|
||||
def __init__(self, *args, delimiter=None, **kwargs):
|
||||
if delimiter and delimiter not in CSV_DELIMITERS.keys():
|
||||
raise ValueError(_("Invalid delimiter name: {name}").format(name=delimiter))
|
||||
self.delimiter = delimiter or 'comma'
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def export(self):
|
||||
if self.format == self.CSV and self.delimiter is not None:
|
||||
delimiter = CSV_DELIMITERS[self.delimiter]
|
||||
return self.dataset.export(self.format, delimiter=delimiter)
|
||||
return super().export()
|
Loading…
Reference in New Issue
Block a user