Răsfoiți Sursa

Consolidate CSV delimiter lookup and allow CSV export without a request

Jeremy Stretch 4 zile în urmă
părinte
comite
57c672e950

+ 9 - 2
netbox/netbox/exporters.py

@@ -79,8 +79,15 @@ class CSVExporter(Exporter):
     tabular = True
 
     def export(self, *, request, queryset, headers=None, rows=None):
-        delimiter = request.user.config.get('csv_delimiter') if request.user.is_authenticated else None
-        return self.write_rows(headers, rows, delimiter=delimiter)
+        return self.write_rows(headers, rows, delimiter=self.get_delimiter(request))
+
+    @staticmethod
+    def get_delimiter(request):
+        """
+        Return the name of the requesting user's preferred CSV delimiter, if any.
+        """
+        user = getattr(request, 'user', None)
+        return user.config.get('csv_delimiter') if user is not None and user.is_authenticated else None
 
     def write_rows(self, headers, rows, delimiter=None):
         """

+ 7 - 1
netbox/netbox/tests/test_exporters.py

@@ -109,6 +109,10 @@ class CSVExporterTestCase(SimpleTestCase):
         with self.assertRaises(ValueError):
             get_exporter('csv').write_rows(self.headers, iter(self.rows), delimiter='invalid')
 
+    def test_export_without_request(self):
+        data = get_exporter('csv').export(request=None, queryset=None, headers=self.headers, rows=iter(self.rows))
+        self.assertEqual(''.join(data), 'Name,Count\r\nSite 1,1\r\n"Site, 2",\r\n')
+
 
 class YAMLExporterTestCase(TestCase):
 
@@ -261,18 +265,20 @@ class ExportViewTestCase(TestCase):
 
     def test_export_table_override(self):
         """
-        Overriding the deprecated export_table() still applies to CSV exports.
+        Overriding the deprecated export_table() still applies to CSV exports, using the user's delimiter.
         """
         class CustomSiteListView(SiteListView):
             def export_table(self, table, columns=None, filename=None, delimiter=None):
                 return super().export_table(table, columns, filename='custom.csv', delimiter=delimiter)
 
+        self.user.config.set('csv_delimiter', 'semicolon', commit=True)
         for params in ({'export': 'table'}, {'export': ''}, {'export': 'table', 'export_format': 'csv'}):
             with self.subTest(params=params):
                 request = RequestFactory().get(self.url, params)
                 request.user = self.user
                 response = CustomSiteListView.as_view()(request)
                 self.assertEqual(response['Content-Disposition'], 'attachment; filename="custom.csv"')
+                self.assertTrue(response.getvalue().decode().startswith('Name;Status'))
 
     def test_export_yaml_override(self):
         """

+ 1 - 2
netbox/netbox/views/generic/bulk_views.py

@@ -280,8 +280,7 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
 
             # TODO: Remove in NetBox v5.0 along with export_table()
             if exporter.slug == 'csv' and type(self).export_table is not ObjectListView.export_table:
-                delimiter = request.user.config.get('csv_delimiter') if request.user.is_authenticated else None
-                return self.export_table(table, columns, delimiter=delimiter)
+                return self.export_table(table, columns, delimiter=exporter.get_delimiter(request))
 
             headers, rows = self.get_export_rows(table, columns)
             data = exporter.export(request=request, queryset=self.queryset, headers=headers, rows=rows)