From 37abb4c8a865379c90e716efb991a5bbdcd32586 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 18 Aug 2025 09:46:57 -0400 Subject: [PATCH] Fix multiselect and multi-object CF filters --- netbox/extras/tests/test_customfields.py | 4 ++-- netbox/netbox/filtersets.py | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/netbox/extras/tests/test_customfields.py b/netbox/extras/tests/test_customfields.py index 8da8fcbf1..c3074aa41 100644 --- a/netbox/extras/tests/test_customfields.py +++ b/netbox/extras/tests/test_customfields.py @@ -1691,8 +1691,8 @@ class CustomFieldModelFilterTest(TestCase): def test_filter_multiselect(self): self.assertEqual(self.filterset({'cf_cf10': ['A']}, self.queryset).qs.count(), 1) self.assertEqual(self.filterset({'cf_cf10': ['A', 'C']}, self.queryset).qs.count(), 2) - self.assertEqual(self.filterset({'cf_cf10': ['null']}, self.queryset).qs.count(), 1) - self.assertEqual(self.filterset({'cf_cf10__empty': True}, self.queryset).qs.count(), 1) # Same as above + self.assertEqual(self.filterset({'cf_cf10': ['null']}, self.queryset).qs.count(), 1) # Contains a literal null + self.assertEqual(self.filterset({'cf_cf10__empty': True}, self.queryset).qs.count(), 2) def test_filter_object(self): manufacturer_ids = Manufacturer.objects.values_list('id', flat=True) diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index f24b4e11c..ea24efe48 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -29,6 +29,13 @@ __all__ = ( 'OrganizationalModelFilterSet', ) +STANDARD_LOOKUPS = ( + 'exact', + 'iexact', + 'in', + 'contains', +) + # # FilterSets @@ -159,7 +166,7 @@ class BaseFilterSet(django_filters.FilterSet): return {} # Skip nonstandard lookup expressions - if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'iexact', 'in']: + if existing_filter.method is not None or existing_filter.lookup_expr not in STANDARD_LOOKUPS: return {} # Choose the lookup expression map based on the filter type