From 90c371dee2c052df5916003d142551f66e5c74e0 Mon Sep 17 00:00:00 2001 From: Martin Hauser Date: Fri, 15 May 2026 20:18:37 +0200 Subject: [PATCH] fix(extras): Handle None ordering in TableConfig validation Prevent TypeError when TableConfig.ordering is None by adding explicit null check in clean(). Add regression test covering unset ordering field. Fixes #22206 --- netbox/extras/models/models.py | 2 +- netbox/extras/tests/test_models.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index f3b8fae61..14cae8d9d 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -658,7 +658,7 @@ class TableConfig(CloningMixin, ChangeLoggedModel): table = self.table_class([]) # Validate ordering columns - for name in self.ordering: + for name in self.ordering or []: if name.startswith('-'): name = name[1:] # Strip leading hyphen if name not in table.columns: diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index 794f216fb..897ecd0c8 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -24,6 +24,7 @@ from extras.models import ( EventRule, ExportTemplate, ImageAttachment, + TableConfig, Tag, TaggedItem, ) @@ -31,6 +32,7 @@ from extras.models.mixins import RenderTemplateMixin from tenancy.models import Tenant, TenantGroup from utilities.exceptions import AbortRequest from utilities.jinja2 import render_jinja2 +from utilities.tables import get_table_for_model from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine @@ -190,6 +192,25 @@ class ImageAttachmentTestCase(TestCase): self.assertCountEqual(storage.files.keys(), {base_name, suffixed_name}) +class TableConfigTestCase(TestCase): + @classmethod + def setUpTestData(cls): + cls.site_ct = ContentType.objects.get_for_model(Site) + cls.table_name = get_table_for_model(Site).__name__ + + def test_clean_accepts_ordering_none(self): + """clean() must accept ordering=None (field is null=True).""" + tc = TableConfig( + object_type=self.site_ct, + table=self.table_name, + name='No ordering', + columns=['name'], + # ordering left unset (defaults to None) + ) + # Must not raise TypeError: 'NoneType' object is not iterable + tc.full_clean() + + class TagTestCase(TestCase): def test_default_ordering_weight_then_name_is_set(self):