diff --git a/changes/192.changed b/changes/192.changed new file mode 100644 index 0000000..edb5840 --- /dev/null +++ b/changes/192.changed @@ -0,0 +1 @@ +Changed all `q` search methods to use `SearchFilter`. \ No newline at end of file diff --git a/changes/226.added b/changes/226.added new file mode 100644 index 0000000..fbce6e2 --- /dev/null +++ b/changes/226.added @@ -0,0 +1 @@ +Added `q` search filters to `AddressFamilyFilterSet` and `PeeringFilterSet`. \ No newline at end of file diff --git a/nautobot_bgp_models/filters.py b/nautobot_bgp_models/filters.py index 08d433e..2480d77 100644 --- a/nautobot_bgp_models/filters.py +++ b/nautobot_bgp_models/filters.py @@ -2,11 +2,11 @@ """FilterSet definitions for nautobot_bgp_models.""" import django_filters -from django.db.models import Q from nautobot.apps.filters import ( BaseFilterSet, CreatedUpdatedModelFilterSetMixin, CustomFieldModelFilterSetMixin, + SearchFilter, StatusModelFilterSetMixin, ) from nautobot.dcim.models import Device @@ -22,17 +22,13 @@ class AutonomousSystemFilterSet( ): """Filtering of AutonomousSystem records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "asn": "icontains", + "description": "icontains", + }, ) - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter(Q(asn__icontains=value) | Q(description__icontains=value)).distinct() - class Meta: model = models.AutonomousSystem fields = ["id", "asn", "status", "tags"] @@ -45,20 +41,15 @@ class AutonomousSystemRangeFilterSet( ): """Filtering of AutonomousSystemRange records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "name": "icontains", + "asn_max": "icontains", + "asn_min": "icontains", + "description": "icontains", + }, ) - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - - return queryset.filter( - Q(name=value) | Q(asn_max__icontains=value) | Q(asn_min__icontains=value) | Q(description__icontains=value) - ).distinct() - class Meta: model = models.AutonomousSystemRange fields = ["id", "name", "asn_min", "asn_max", "tags"] @@ -69,9 +60,10 @@ class BGPRoutingInstanceFilterSet( ): """Filtering of BGPRoutingInstance records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "device__name": "icontains", + }, ) autonomous_system = django_filters.ModelMultipleChoiceFilter( @@ -97,19 +89,15 @@ class Meta: model = models.BGPRoutingInstance fields = ["id", "autonomous_system", "tags"] - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter(Q(device__name__icontains=value)).distinct() - class PeerGroupFilterSet(RoleModelFilterSetMixin, BaseFilterSet): """Filtering of PeerGroup records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "name": "icontains", + "description": "icontains", + }, ) autonomous_system = django_filters.ModelMultipleChoiceFilter( @@ -144,19 +132,15 @@ class Meta: model = models.PeerGroup fields = ["id", "name", "enabled"] - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter(Q(name__icontains=value) | Q(description__icontains=value)).distinct() - class PeerGroupTemplateFilterSet(RoleModelFilterSetMixin, BaseFilterSet): """Filtering of PeerGroupTemplate records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "name": "icontains", + "description": "icontains", + }, ) autonomous_system = django_filters.ModelMultipleChoiceFilter( @@ -170,19 +154,15 @@ class Meta: model = models.PeerGroupTemplate fields = ["id", "name", "enabled"] - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter(Q(name__icontains=value) | Q(description__icontains=value)).distinct() - class PeerEndpointFilterSet(RoleModelFilterSetMixin, BaseFilterSet): """Filtering of PeerEndpoint records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "routing_instance__device__name": "iexact", + "description": "icontains", + }, ) device = django_filters.ModelMultipleChoiceFilter( @@ -215,14 +195,6 @@ class Meta: model = models.PeerEndpoint fields = ["id", "enabled"] - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter( - Q(routing_instance__device__name__iexact=value) | Q(description__icontains=value) - ).distinct() - class PeeringFilterSet( BaseFilterSet, @@ -235,6 +207,12 @@ class PeeringFilterSet( # TODO(mzb): Add in-memory filtering for Provider, ASN, IP Address, ... # this requires to consider inheritance methods. + q = SearchFilter( + filter_predicates={ + "endpoints__routing_instance__device__name": "icontains", + }, + ) + device = django_filters.ModelMultipleChoiceFilter( field_name="endpoints__routing_instance__device__name", queryset=Device.objects.all(), @@ -271,6 +249,12 @@ class Meta: class AddressFamilyFilterSet(BaseFilterSet, CreatedUpdatedModelFilterSetMixin, CustomFieldModelFilterSetMixin): """Filtering of AddressFamily records.""" + q = SearchFilter( + filter_predicates={ + "routing_instance__device__name": "iexact", + }, + ) + afi_safi = django_filters.MultipleChoiceFilter(choices=choices.AFISAFIChoices) routing_instance = django_filters.ModelMultipleChoiceFilter( @@ -300,9 +284,12 @@ class Meta: class PeerGroupAddressFamilyFilterSet(BaseFilterSet, CreatedUpdatedModelFilterSetMixin, CustomFieldModelFilterSetMixin): """Filtering of PeerGroupAddressFamily records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "afi_safi": "icontains", + "peer_group__name": "icontains", + "peer_group__description": "icontains", + }, ) afi_safi = django_filters.MultipleChoiceFilter(choices=choices.AFISAFIChoices) @@ -320,25 +307,18 @@ class Meta: "peer_group", ] - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter( - Q(afi_safi__icontains=value) - | Q(peer_group__name__icontains=value) - | Q(peer_group__description__icontains=value) - ).distinct() - class PeerEndpointAddressFamilyFilterSet( BaseFilterSet, CreatedUpdatedModelFilterSetMixin, CustomFieldModelFilterSetMixin ): """Filtering of PeerEndpointAddressFamily records.""" - q = django_filters.CharFilter( - method="search", - label="Search", + q = SearchFilter( + filter_predicates={ + "afi_safi": "icontains", + "peer_endpoint__routing_instance__device__name": "iexact", + "peer_endpoint__description": "icontains", + }, ) afi_safi = django_filters.MultipleChoiceFilter(choices=choices.AFISAFIChoices) @@ -355,13 +335,3 @@ class Meta: "afi_safi", "peer_endpoint", ] - - def search(self, queryset, name, value): # pylint: disable=unused-argument - """Free-text search method implementation.""" - if not value.strip(): - return queryset - return queryset.filter( - Q(afi_safi__icontains=value) - | Q(peer_endpoint__routing_instance__device__name__iexact=value) - | Q(peer_endpoint__description__icontains=value) - ).distinct() diff --git a/nautobot_bgp_models/tests/test_filters.py b/nautobot_bgp_models/tests/test_filters.py index 2893d11..05f8626 100644 --- a/nautobot_bgp_models/tests/test_filters.py +++ b/nautobot_bgp_models/tests/test_filters.py @@ -1,9 +1,9 @@ """Unit test automation for FilterSet classes in nautobot_bgp_models.""" from django.contrib.contenttypes.models import ContentType -from django.test import TestCase # from nautobot.circuits.models import Provider +from nautobot.core.testing import FilterTestCases from nautobot.dcim.choices import InterfaceTypeChoices from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer from nautobot.extras.models import Role, Status @@ -12,7 +12,7 @@ from nautobot_bgp_models import choices, filters, models -class AutonomousSystemTestCase(TestCase): +class AutonomousSystemTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of AutonomousSystem records.""" queryset = models.AutonomousSystem.objects.all() @@ -55,8 +55,13 @@ def test_status(self): params = {"status": [self.status_primary_asn.name, self.status_remote_asn.name]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_search(self): + """Test filtering by Q search value.""" + self.assertEqual(self.filterset({"q": "420"}, self.queryset).qs.count(), 3) + self.assertEqual(self.filterset({"q": "another"}, self.queryset).qs.count(), 1) + -class AutonomousSystemRangeTestCase(TestCase): +class AutonomousSystemRangeTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of AutonomousSystemRange records.""" queryset = models.AutonomousSystemRange.objects.all() @@ -94,8 +99,12 @@ def test_min_max(self): params = {"asn_max": [3000]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_search(self): + """Test filtering by Q search value.""" + self.assertEqual(self.filterset({"q": "DC"}, self.queryset).qs.count(), 2) + -class PeerGroupTestCase(TestCase): +class PeerGroupTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of PeerGroup records.""" queryset = models.PeerGroup.objects.all() @@ -219,7 +228,7 @@ def test_routing_instance(self): ) -class PeerEndpointTestCase(TestCase): +class PeerEndpointTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of PeerEndpoint records.""" queryset = models.PeerEndpoint.objects.all() @@ -309,7 +318,7 @@ def setUpTestData(cls): # pylint: disable=too-many-locals def test_search(self): """Test text search.""" self.assertEqual(self.filterset({"q": "Device 1"}, self.queryset).qs.count(), 2) - self.assertEqual(self.filterset({"q": "device 1"}, self.queryset).qs.count(), 2) + self.assertEqual(self.filterset({"q": "dev"}, self.queryset).qs.count(), 0) def test_id(self): """Test filtering by ID (primary key).""" @@ -342,7 +351,7 @@ def test_device_id(self): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) -class PeeringTestCase(TestCase): +class PeeringTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of Peering records.""" queryset = models.Peering.objects.all() @@ -656,8 +665,13 @@ def test_peer_endpoint_role(self): # params = {"address": ["10.1.1.3", "10.1.1.5"]} # self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_search(self): + """Test filtering by Q search value.""" + self.assertEqual(self.filterset({"q": "device1"}, self.queryset).qs.count(), 3) + self.assertEqual(self.filterset({"q": "device2"}, self.queryset).qs.count(), 2) + -class AddressFamilyTestCase(TestCase): +class AddressFamilyTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of AddressFamily records.""" queryset = models.AddressFamily.objects.all() @@ -742,8 +756,12 @@ def test_afi_safi(self): def test_device(self): pass + def test_search(self): + """Test filtering by Q search value.""" + self.assertEqual(self.filterset({"q": "Device 1"}, self.queryset).qs.count(), 3) + -class PeerGroupAddressFamilyTestCase(TestCase): +class PeerGroupAddressFamilyTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of PeerGroupAddressFamily records.""" queryset = models.PeerGroupAddressFamily.objects.all() @@ -833,7 +851,7 @@ def test_peer_endpoint(self): self.assertEqual(self.filterset({"peer_group": [self.pg1.pk]}, self.queryset).qs.count(), 2) -class PeerEndpointAddressFamilyTestCase(TestCase): +class PeerEndpointAddressFamilyTestCase(FilterTestCases.BaseFilterTestCase): """Test filtering of PeerEndpointAddressFamily records.""" queryset = models.PeerEndpointAddressFamily.objects.all() @@ -951,8 +969,9 @@ def setUpTestData(cls): def test_search(self): """Test text search.""" - self.assertEqual(self.filterset({"q": "ipv4_unicast"}, self.queryset).qs.count(), 3) - self.assertEqual(self.filterset({"q": self.pe1.description}, self.queryset).qs.count(), 2) + self.assertEqual(self.filterset({"q": "ipv4_uni"}, self.queryset).qs.count(), 3) + self.assertEqual(self.filterset({"q": "endpoint"}, self.queryset).qs.count(), 2) + self.assertEqual(self.filterset({"q": "Device 1"}, self.queryset).qs.count(), 3) def test_id(self): """Test filtering by ID (primary key)."""