Fixes #9657: Fix filtering for custom fields and webhooks in the UI

This commit is contained in:
jeremystretch 2022-07-08 14:59:16 -04:00
parent 55b3e4eeb3
commit a40ab9ffb1
4 changed files with 85 additions and 10 deletions

View File

@ -14,6 +14,7 @@
* [#8854](https://github.com/netbox-community/netbox/issues/8854) - Fix `REMOTE_AUTH_DEFAULT_GROUPS` for social-auth backends * [#8854](https://github.com/netbox-community/netbox/issues/8854) - Fix `REMOTE_AUTH_DEFAULT_GROUPS` for social-auth backends
* [#9575](https://github.com/netbox-community/netbox/issues/9575) - Fix AttributeError exception for FHRP group with an IP address assigned * [#9575](https://github.com/netbox-community/netbox/issues/9575) - Fix AttributeError exception for FHRP group with an IP address assigned
* [#9597](https://github.com/netbox-community/netbox/issues/9597) - Include `installed_module` in module bay REST API serializer * [#9597](https://github.com/netbox-community/netbox/issues/9597) - Include `installed_module` in module bay REST API serializer
* [#9657](https://github.com/netbox-community/netbox/issues/9657) - Fix filtering for custom fields and webhooks in the UI
* [#9682](https://github.com/netbox-community/netbox/issues/9682) - Fix bulk assignment of ASNs to sites * [#9682](https://github.com/netbox-community/netbox/issues/9682) - Fix bulk assignment of ASNs to sites
--- ---

View File

@ -32,6 +32,9 @@ class WebhookFilterSet(BaseFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
content_type_id = MultiValueNumberFilter(
field_name='content_types__id'
)
content_types = ContentTypeFilter() content_types = ContentTypeFilter()
http_method = django_filters.MultipleChoiceFilter( http_method = django_filters.MultipleChoiceFilter(
choices=WebhookHttpMethodChoices choices=WebhookHttpMethodChoices
@ -40,8 +43,8 @@ class WebhookFilterSet(BaseFilterSet):
class Meta: class Meta:
model = Webhook model = Webhook
fields = [ fields = [
'id', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled', 'id', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled', 'http_method',
'http_method', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path',
] ]
def search(self, queryset, name, value): def search(self, queryset, name, value):
@ -58,11 +61,17 @@ class CustomFieldFilterSet(BaseFilterSet):
method='search', method='search',
label='Search', label='Search',
) )
type = django_filters.MultipleChoiceFilter(
choices=CustomFieldTypeChoices
)
content_type_id = MultiValueNumberFilter(
field_name='content_types__id'
)
content_types = ContentTypeFilter() content_types = ContentTypeFilter()
class Meta: class Meta:
model = CustomField model = CustomField
fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight', 'description'] fields = ['id', 'name', 'required', 'filter_logic', 'weight', 'description']
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():

View File

@ -32,12 +32,13 @@ __all__ = (
class CustomFieldFilterForm(FilterForm): class CustomFieldFilterForm(FilterForm):
fieldsets = ( fieldsets = (
(None, ('q',)), (None, ('q',)),
('Attributes', ('type', 'content_types', 'weight', 'required')), ('Attributes', ('type', 'content_type_id', 'weight', 'required')),
) )
content_types = ContentTypeMultipleChoiceField( content_type_id = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
required=False required=False,
label='Object type'
) )
type = MultipleChoiceField( type = MultipleChoiceField(
choices=CustomFieldTypeChoices, choices=CustomFieldTypeChoices,
@ -110,13 +111,14 @@ class ExportTemplateFilterForm(FilterForm):
class WebhookFilterForm(FilterForm): class WebhookFilterForm(FilterForm):
fieldsets = ( fieldsets = (
(None, ('q',)), (None, ('q',)),
('Attributes', ('content_types', 'http_method', 'enabled')), ('Attributes', ('content_type_id', 'http_method', 'enabled')),
('Events', ('type_create', 'type_update', 'type_delete')), ('Events', ('type_create', 'type_update', 'type_delete')),
) )
content_types = ContentTypeMultipleChoiceField( content_type_id = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
required=False required=False,
label='Object type'
) )
http_method = MultipleChoiceField( http_method = MultipleChoiceField(
choices=WebhookHttpMethodChoices, choices=WebhookHttpMethodChoices,

View File

@ -7,7 +7,9 @@ from django.test import TestCase
from circuits.models import Provider from circuits.models import Provider
from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup
from extras.choices import JournalEntryKindChoices, ObjectChangeActionChoices from extras.choices import (
CustomFieldTypeChoices, CustomFieldFilterLogicChoices, JournalEntryKindChoices, ObjectChangeActionChoices,
)
from extras.filtersets import * from extras.filtersets import *
from extras.models import * from extras.models import *
from ipam.models import IPAddress from ipam.models import IPAddress
@ -16,6 +18,65 @@ from utilities.testing import BaseFilterSetTests, ChangeLoggedFilterSetTests, cr
from virtualization.models import Cluster, ClusterGroup, ClusterType from virtualization.models import Cluster, ClusterGroup, ClusterType
class CustomFieldTestCase(TestCase, BaseFilterSetTests):
queryset = CustomField.objects.all()
filterset = CustomFieldFilterSet
@classmethod
def setUpTestData(cls):
content_types = ContentType.objects.filter(model__in=['site', 'rack', 'device'])
custom_fields = (
CustomField(
name='Custom Field 1',
type=CustomFieldTypeChoices.TYPE_TEXT,
required=True,
weight=100,
filter_logic=CustomFieldFilterLogicChoices.FILTER_LOOSE
),
CustomField(
name='Custom Field 2',
type=CustomFieldTypeChoices.TYPE_INTEGER,
required=False,
weight=200,
filter_logic=CustomFieldFilterLogicChoices.FILTER_EXACT
),
CustomField(
name='Custom Field 3',
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
required=False,
weight=300,
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
),
)
CustomField.objects.bulk_create(custom_fields)
custom_fields[0].content_types.add(content_types[0])
custom_fields[1].content_types.add(content_types[1])
custom_fields[2].content_types.add(content_types[2])
def test_name(self):
params = {'name': ['Custom Field 1', 'Custom Field 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_content_types(self):
params = {'content_types': 'dcim.site'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'content_type_id': [ContentType.objects.get_for_model(Site).pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_required(self):
params = {'required': True}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_weight(self):
params = {'weight': [100, 200]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_filter_logic(self):
params = {'filter_logic': CustomFieldFilterLogicChoices.FILTER_LOOSE}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class WebhookTestCase(TestCase, BaseFilterSetTests): class WebhookTestCase(TestCase, BaseFilterSetTests):
queryset = Webhook.objects.all() queryset = Webhook.objects.all()
filterset = WebhookFilterSet filterset = WebhookFilterSet
@ -62,6 +123,8 @@ class WebhookTestCase(TestCase, BaseFilterSetTests):
def test_content_types(self): def test_content_types(self):
params = {'content_types': 'dcim.site'} params = {'content_types': 'dcim.site'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
params = {'content_type_id': [ContentType.objects.get_for_model(Site).pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_type_create(self): def test_type_create(self):
params = {'type_create': True} params = {'type_create': True}