Просмотр исходного кода

Test export ordering and document the ordering of the queryset passed to exporters

Jeremy Stretch 3 дней назад
Родитель
Сommit
eba0cbd00f
2 измененных файлов с 26 добавлено и 1 удалено
  1. 1 1
      docs/plugins/development/exporters.md
  2. 25 0
      netbox/netbox/tests/test_exporters.py

+ 1 - 1
docs/plugins/development/exporters.md

@@ -51,7 +51,7 @@ class VendorDeviceTypeExporter(Exporter):
         ...
 ```
 
-The queryset passed to an exporter has the user's filters applied, and is restricted to objects the user has permission to view. `export()` returns the exported data as a string or bytes, or as an iterable of chunks. NetBox streams an iterable to the client if [`STREAMING_EXPORTS`](../../configuration/miscellaneous.md#streaming_exports) is enabled; otherwise, it collects the chunks before responding.
+The queryset passed to an exporter has the user's filters applied, and is restricted to objects the user has permission to view. It isn't sorted to match the list view's table; only the rows passed to a tabular exporter follow the table's sort order. `export()` returns the exported data as a string or bytes, or as an iterable of chunks. NetBox streams an iterable to the client if [`STREAMING_EXPORTS`](../../configuration/miscellaneous.md#streaming_exports) is enabled; otherwise, it collects the chunks before responding.
 
 The `register_exporter()` decorator registers an exporter with NetBox. Exporters can be defined anywhere within a plugin, but must be imported during plugin initialization, under the PluginConfig's `ready()` method:
 

+ 25 - 0
netbox/netbox/tests/test_exporters.py

@@ -4,6 +4,7 @@ from io import StringIO
 from unittest import skipIf
 from unittest.mock import patch
 
+import yaml
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured
 from django.db import connection
@@ -172,6 +173,30 @@ class ExportViewTestCase(TestCase):
         response = self.client.get(f'{self.url}?export=table&export_format=csv&q=Site 2')
         self.assertEqual(self.get_csv_rows(response)[1:], [['Site 2', 'Active']])
 
+    def test_export_table_ordering(self):
+        """
+        Table exports follow the table's sort order.
+        """
+        for streaming in (False, True):
+            for params in ('export=table', 'export'):
+                with self.subTest(streaming=streaming, params=params), override_settings(STREAMING_EXPORTS=streaming):
+                    response = self.client.get(f'{self.url}?{params}&sort=-name')
+                    rows = list(csv.reader(StringIO(response.getvalue().decode())))
+                    self.assertEqual([row[0] for row in rows[1:]], ['Site 3', 'Site 2', 'Site 1'])
+
+    def test_export_yaml_ordering(self):
+        """
+        YAML exports use the queryset's ordering, not the table's sort order.
+        """
+        manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
+        for i in range(1, 4):
+            DeviceType.objects.create(manufacturer=manufacturer, model=f'Device Type {i}', slug=f'device-type-{i}')
+        self.add_permissions('dcim.view_devicetype')
+
+        response = self.client.get(f'{reverse("dcim:devicetype_list")}?export&sort=-model')
+        models = [data['model'] for data in yaml.safe_load_all(response.content)]
+        self.assertEqual(models, ['Device Type 1', 'Device Type 2', 'Device Type 3'])
+
     def test_export_chunked_only_if_streaming(self):
         """
         Table exports fetch records in chunks (using a server-side cursor) only if STREAMING_EXPORTS is enabled.