Skip to content

Commit

Permalink
Closes: #16837 - Fix type__empty filter in character-based filters (#…
Browse files Browse the repository at this point in the history
…17574)

* Fix type__empty filter in character-based filters

* Add tests
  • Loading branch information
bctiemann authored Sep 24, 2024
1 parent 9c9c4fb commit 116a423
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
4 changes: 4 additions & 0 deletions netbox/dcim/tests/test_filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5247,6 +5247,10 @@ def test_length_unit(self):
def test_type(self):
params = {'type': [CableTypeChoices.TYPE_CAT3, CableTypeChoices.TYPE_CAT5E]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
params = {'type__empty': 'true'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 8)
params = {'type__empty': 'false'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)

def test_status(self):
params = {'status': [LinkStatusChoices.STATUS_CONNECTED]}
Expand Down
7 changes: 5 additions & 2 deletions netbox/netbox/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def _get_filter_lookup_dict(existing_filter):
django_filters.ModelChoiceFilter,
django_filters.ModelMultipleChoiceFilter,
TagFilter
)) or existing_filter.extra.get('choices'):
)):
# These filter types support only negation
return FILTER_NEGATION_LOOKUP_MAP

Expand Down Expand Up @@ -172,21 +172,24 @@ def get_additional_lookups(cls, existing_filter_name, existing_filter):
# Create new filters for each lookup expression in the map
for lookup_name, lookup_expr in lookup_map.items():
new_filter_name = f'{existing_filter_name}__{lookup_name}'
existing_filter_extra = deepcopy(existing_filter.extra)

try:
if existing_filter_name in cls.declared_filters:
# The filter field has been explicitly defined on the filterset class so we must manually
# create the new filter with the same type because there is no guarantee the defined type
# is the same as the default type for the field
resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid
for field_to_remove in ('choices', 'null_value'):
existing_filter_extra.pop(field_to_remove, None)
filter_cls = django_filters.BooleanFilter if lookup_expr == 'empty' else type(existing_filter)
new_filter = filter_cls(
field_name=field_name,
lookup_expr=lookup_expr,
label=existing_filter.label,
exclude=existing_filter.exclude,
distinct=existing_filter.distinct,
**existing_filter.extra
**existing_filter_extra
)
elif hasattr(existing_filter, 'custom_field'):
# Filter is for a custom field
Expand Down

0 comments on commit 116a423

Please sign in to comment.