Skip to content

Commit

Permalink
Fixes #13606: Fix filtering by null for multiselect custom fields
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremystretch committed Dec 26, 2023
1 parent 99467e8 commit d91c525
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 9 deletions.
4 changes: 1 addition & 3 deletions netbox/extras/models/customfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from django.core.validators import RegexValidator, ValidationError
from django.db import models
from django.urls import reverse
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

Expand Down Expand Up @@ -571,8 +570,7 @@ def to_filter(self, lookup_expr=None):

# Multiselect
elif self.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
filter_class = filters.MultiValueCharFilter
kwargs['lookup_expr'] = 'has_key'
filter_class = filters.MultiValueArrayFilter

# Object
elif self.type == CustomFieldTypeChoices.TYPE_OBJECT:
Expand Down
13 changes: 7 additions & 6 deletions netbox/extras/tests/test_customfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,7 @@ def setUpTestData(cls):

choice_set = CustomFieldChoiceSet.objects.create(
name='Custom Field Choice Set 1',
extra_choices=(('a', 'A'), ('b', 'B'), ('c', 'C'), ('x', 'X'))
extra_choices=(('a', 'A'), ('b', 'B'), ('c', 'C'))
)

# Integer filtering
Expand Down Expand Up @@ -1435,7 +1435,7 @@ def setUpTestData(cls):
'cf7': 'http://a.example.com',
'cf8': 'http://a.example.com',
'cf9': 'A',
'cf10': ['A', 'X'],
'cf10': ['A', 'B'],
'cf11': manufacturers[0].pk,
'cf12': [manufacturers[0].pk, manufacturers[3].pk],
}),
Expand All @@ -1449,7 +1449,7 @@ def setUpTestData(cls):
'cf7': 'http://b.example.com',
'cf8': 'http://b.example.com',
'cf9': 'B',
'cf10': ['B', 'X'],
'cf10': ['B', 'C'],
'cf11': manufacturers[1].pk,
'cf12': [manufacturers[1].pk, manufacturers[3].pk],
}),
Expand All @@ -1463,7 +1463,7 @@ def setUpTestData(cls):
'cf7': 'http://c.example.com',
'cf8': 'http://c.example.com',
'cf9': 'C',
'cf10': ['C', 'X'],
'cf10': None,
'cf11': manufacturers[2].pk,
'cf12': [manufacturers[2].pk, manufacturers[3].pk],
}),
Expand Down Expand Up @@ -1531,8 +1531,9 @@ def test_filter_select(self):
self.assertEqual(self.filterset({'cf_cf9': ['A', 'B']}, self.queryset).qs.count(), 2)

def test_filter_multiselect(self):
self.assertEqual(self.filterset({'cf_cf10': ['A', 'B']}, self.queryset).qs.count(), 2)
self.assertEqual(self.filterset({'cf_cf10': ['X']}, self.queryset).qs.count(), 3)
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)

def test_filter_object(self):
manufacturer_ids = Manufacturer.objects.values_list('id', flat=True)
Expand Down
16 changes: 16 additions & 0 deletions netbox/utilities/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
__all__ = (
'ContentTypeFilter',
'MACAddressFilter',
'MultiValueArrayFilter',
'MultiValueCharFilter',
'MultiValueDateFilter',
'MultiValueDateTimeFilter',
Expand Down Expand Up @@ -85,6 +86,21 @@ class MultiValueTimeFilter(django_filters.MultipleChoiceFilter):
field_class = multivalue_field_factory(forms.TimeField)


@extend_schema_field(OpenApiTypes.STR)
class MultiValueArrayFilter(django_filters.MultipleChoiceFilter):
field_class = multivalue_field_factory(forms.CharField)

def __init__(self, *args, lookup_expr='contains', **kwargs):
# Set default lookup_expr to 'contains'
super().__init__(*args, lookup_expr=lookup_expr, **kwargs)

def get_filter_predicate(self, v):
# If filtering for null values, ignore lookup_expr
if v is None:
return {self.field_name: None}
return super().get_filter_predicate(v)


class MACAddressFilter(django_filters.CharFilter):
pass

Expand Down

0 comments on commit d91c525

Please sign in to comment.