From e902b13edb32960c5ad4951924bc138617e8a93a Mon Sep 17 00:00:00 2001 From: Martin Hauser Date: Thu, 26 Mar 2026 19:48:09 +0100 Subject: [PATCH] fix(tables): Disable ordering on non-orderable accessor columns Mark provider, member, and action_object columns as non-orderable since they use complex accessors that cannot be sorted. Add regression tests to verify all orderable columns render without exceptions. Fixes table rendering errors when attempting to sort columns with multi-level field accessors that don't support database ordering. --- netbox/circuits/tables/circuits.py | 6 +++-- netbox/circuits/tests/test_tables.py | 39 +++++++++++++++++++++++----- netbox/extras/tables/tables.py | 3 ++- netbox/extras/tests/test_tables.py | 24 +++++++++++++++++ 4 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 netbox/extras/tests/test_tables.py diff --git a/netbox/circuits/tables/circuits.py b/netbox/circuits/tables/circuits.py index 2b024f580..9ee9bd37b 100644 --- a/netbox/circuits/tables/circuits.py +++ b/netbox/circuits/tables/circuits.py @@ -190,14 +190,16 @@ class CircuitGroupAssignmentTable(NetBoxTable): provider = tables.Column( accessor='member__provider', verbose_name=_('Provider'), - linkify=True + orderable=False, + linkify=True, ) member_type = columns.ContentTypeColumn( verbose_name=_('Type') ) member = tables.Column( verbose_name=_('Circuit'), - linkify=True + orderable=False, + linkify=True, ) priority = tables.Column( verbose_name=_('Priority'), diff --git a/netbox/circuits/tests/test_tables.py b/netbox/circuits/tests/test_tables.py index 0e3ac1156..fd142f01b 100644 --- a/netbox/circuits/tests/test_tables.py +++ b/netbox/circuits/tests/test_tables.py @@ -1,23 +1,48 @@ from django.test import RequestFactory, TestCase, tag -from circuits.models import CircuitTermination -from circuits.tables import CircuitTerminationTable +from circuits.models import CircuitGroupAssignment, CircuitTermination +from circuits.tables import CircuitGroupAssignmentTable, CircuitTerminationTable @tag('regression') class CircuitTerminationTableTest(TestCase): def test_every_orderable_field_does_not_throw_exception(self): terminations = CircuitTermination.objects.all() - disallowed = {'actions', } + disallowed = { + 'actions', + } orderable_columns = [ - column.name for column in CircuitTerminationTable(terminations).columns + column.name + for column in CircuitTerminationTable(terminations).columns if column.orderable and column.name not in disallowed ] - fake_request = RequestFactory().get("/") + fake_request = RequestFactory().get('/') for col in orderable_columns: - for dir in ('-', ''): + for direction in ('-', ''): table = CircuitTerminationTable(terminations) - table.order_by = f'{dir}{col}' + table.order_by = f'{direction}{col}' + table.as_html(fake_request) + + +@tag('regression') +class CircuitGroupAssignmentTableTest(TestCase): + def test_every_orderable_field_does_not_throw_exception(self): + assignment = CircuitGroupAssignment.objects.all() + disallowed = { + 'actions', + } + + orderable_columns = [ + column.name + for column in CircuitGroupAssignmentTable(assignment).columns + if column.orderable and column.name not in disallowed + ] + fake_request = RequestFactory().get('/') + + for col in orderable_columns: + for direction in ('-', ''): + table = CircuitGroupAssignmentTable(assignment) + table.order_by = f'{direction}{col}' table.as_html(fake_request) diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index a4026fe39..cc1165e7c 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -510,8 +510,9 @@ class EventRuleTable(NetBoxTable): verbose_name=_('Type'), ) action_object = tables.Column( - linkify=True, verbose_name=_('Object'), + orderable=False, + linkify=True, ) object_types = columns.ContentTypesColumn( verbose_name=_('Object Types'), diff --git a/netbox/extras/tests/test_tables.py b/netbox/extras/tests/test_tables.py new file mode 100644 index 000000000..7fb6380c9 --- /dev/null +++ b/netbox/extras/tests/test_tables.py @@ -0,0 +1,24 @@ +from django.test import RequestFactory, TestCase, tag + +from extras.models import EventRule +from extras.tables import EventRuleTable + + +@tag('regression') +class EventRuleTableTest(TestCase): + def test_every_orderable_field_does_not_throw_exception(self): + rule = EventRule.objects.all() + disallowed = { + 'actions', + } + + orderable_columns = [ + column.name for column in EventRuleTable(rule).columns if column.orderable and column.name not in disallowed + ] + fake_request = RequestFactory().get('/') + + for col in orderable_columns: + for direction in ('-', ''): + table = EventRuleTable(rule) + table.order_by = f'{direction}{col}' + table.as_html(fake_request)