Fixes #9705: Support filter expressions for the serial field on racks, devices, and inventory items

This commit is contained in:
jeremystretch 2022-07-20 10:39:36 -04:00
parent 1c9db2d9f8
commit 17e00ac040
4 changed files with 19 additions and 13 deletions

View File

@ -4,6 +4,7 @@
### Enhancements ### Enhancements
* [#9705](https://github.com/netbox-community/netbox/issues/9705) - Support filter expressions for the `serial` field on racks, devices, and inventory items
* [#9741](https://github.com/netbox-community/netbox/issues/9741) - Check for UserConfig instance during user login * [#9741](https://github.com/netbox-community/netbox/issues/9741) - Check for UserConfig instance during user login
* [#9745](https://github.com/netbox-community/netbox/issues/9745) - Add wireless LANs and links to global search * [#9745](https://github.com/netbox-community/netbox/issues/9745) - Add wireless LANs and links to global search

View File

@ -307,7 +307,7 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label='Role (slug)',
) )
serial = django_filters.CharFilter( serial = MultiValueCharFilter(
lookup_expr='iexact' lookup_expr='iexact'
) )
@ -1002,10 +1002,13 @@ class ModuleFilterSet(NetBoxModelFilterSet):
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device (ID)', label='Device (ID)',
) )
serial = MultiValueCharFilter(
lookup_expr='iexact'
)
class Meta: class Meta:
model = Module model = Module
fields = ['id', 'serial', 'asset_tag'] fields = ['id', 'asset_tag']
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():
@ -1400,7 +1403,7 @@ class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
) )
component_type = ContentTypeFilter() component_type = ContentTypeFilter()
component_id = MultiValueNumberFilter() component_id = MultiValueNumberFilter()
serial = django_filters.CharFilter( serial = MultiValueCharFilter(
lookup_expr='iexact' lookup_expr='iexact'
) )

View File

@ -494,10 +494,10 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_serial(self): def test_serial(self):
params = {'serial': 'ABC'} params = {'serial': ['ABC', 'DEF']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'serial': 'abc'} params = {'serial': ['abc', 'def']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_tenant(self): def test_tenant(self):
tenants = Tenant.objects.all()[:2] tenants = Tenant.objects.all()[:2]
@ -1860,7 +1860,9 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
def test_serial(self): def test_serial(self):
params = {'asset_tag': ['A', 'B']} params = {'serial': ['A', 'B']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'serial': ['a', 'b']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_asset_tag(self): def test_asset_tag(self):
@ -3413,10 +3415,10 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_serial(self): def test_serial(self):
params = {'serial': 'ABC'} params = {'serial': ['ABC', 'DEF']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'serial': 'abc'} params = {'serial': ['abc', 'def']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_component_type(self): def test_component_type(self):
params = {'component_type': 'dcim.interface'} params = {'component_type': 'dcim.interface'}

View File

@ -125,7 +125,7 @@ class BaseFilterSet(django_filters.FilterSet):
return {} return {}
# Skip nonstandard lookup expressions # Skip nonstandard lookup expressions
if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']: if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'iexact', 'in']:
return {} return {}
# Choose the lookup expression map based on the filter type # Choose the lookup expression map based on the filter type