Explorar o código

fixes #2835 - certain model filters did not support the q query param

John Anderson %!s(int64=7) %!d(string=hai) anos
pai
achega
613e8f05c2

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ v2.5.5 (FUTURE)
 
 * [#2824](https://github.com/digitalocean/netbox/issues/2824) - Fix template exception when viewing rack elevations list
 * [#2833](https://github.com/digitalocean/netbox/issues/2833) - Fix form widget for front port template creation
+* [#2835](https://github.com/digitalocean/netbox/issues/2835) - Fix certain model filters did not support the `q` query param
 
 ---
 

+ 2 - 2
netbox/circuits/filters.py

@@ -4,7 +4,7 @@ from django.db.models import Q
 from dcim.models import Site
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from .constants import CIRCUIT_STATUS_CHOICES
 from .models import Provider, Circuit, CircuitTermination, CircuitType
 
@@ -47,7 +47,7 @@ class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
         )
 
 
-class CircuitTypeFilter(django_filters.FilterSet):
+class CircuitTypeFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = CircuitType

+ 19 - 34
netbox/dcim/filters.py

@@ -8,7 +8,7 @@ from netaddr.core import AddrFormatError
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 from utilities.constants import COLOR_CHOICES
-from utilities.filters import NullableCharFieldFilter, NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter
 from virtualization.models import Cluster
 from .constants import *
 from .models import (
@@ -19,11 +19,7 @@ from .models import (
 )
 
 
-class RegionFilter(django_filters.FilterSet):
-    q = django_filters.CharFilter(
-        method='search',
-        label='Search',
-    )
+class RegionFilter(NameSlugSearchFilterSet):
     parent_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Region.objects.all(),
         label='Parent region (ID)',
@@ -39,15 +35,6 @@ class RegionFilter(django_filters.FilterSet):
         model = Region
         fields = ['name', 'slug']
 
-    def search(self, queryset, name, value):
-        if not value.strip():
-            return queryset
-        qs_filter = (
-            Q(name__icontains=value) |
-            Q(slug__icontains=value)
-        )
-        return queryset.filter(qs_filter)
-
 
 class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
     id__in = NumericInFilter(
@@ -119,11 +106,7 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
         )
 
 
-class RackGroupFilter(django_filters.FilterSet):
-    q = django_filters.CharFilter(
-        method='search',
-        label='Search',
-    )
+class RackGroupFilter(NameSlugSearchFilterSet):
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         label='Site (ID)',
@@ -139,17 +122,8 @@ class RackGroupFilter(django_filters.FilterSet):
         model = RackGroup
         fields = ['site_id', 'name', 'slug']
 
-    def search(self, queryset, name, value):
-        if not value.strip():
-            return queryset
-        qs_filter = (
-            Q(name__icontains=value) |
-            Q(slug__icontains=value)
-        )
-        return queryset.filter(qs_filter)
 
-
-class RackRoleFilter(django_filters.FilterSet):
+class RackRoleFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = RackRole
@@ -303,7 +277,7 @@ class RackReservationFilter(django_filters.FilterSet):
         )
 
 
-class ManufacturerFilter(django_filters.FilterSet):
+class ManufacturerFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = Manufacturer
@@ -393,7 +367,7 @@ class DeviceTypeFilter(CustomFieldFilterSet):
         )
 
 
-class DeviceTypeComponentFilterSet(django_filters.FilterSet):
+class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet):
     devicetype_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DeviceType.objects.all(),
         field_name='device_type_id',
@@ -457,14 +431,14 @@ class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
         fields = ['name']
 
 
-class DeviceRoleFilter(django_filters.FilterSet):
+class DeviceRoleFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = DeviceRole
         fields = ['name', 'slug', 'color', 'vm_role']
 
 
-class PlatformFilter(django_filters.FilterSet):
+class PlatformFilter(NameSlugSearchFilterSet):
     manufacturer_id = django_filters.ModelMultipleChoiceFilter(
         field_name='manufacturer',
         queryset=Manufacturer.objects.all(),
@@ -696,6 +670,10 @@ class DeviceFilter(CustomFieldFilterSet):
 
 
 class DeviceComponentFilterSet(django_filters.FilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
     device_id = django_filters.ModelChoiceFilter(
         queryset=Device.objects.all(),
         label='Device (ID)',
@@ -707,6 +685,13 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
     )
     tag = TagFilter()
 
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        return queryset.filter(
+            Q(name__icontains=value)
+        )
+
 
 class ConsolePortFilter(DeviceComponentFilterSet):
     cabled = django_filters.BooleanFilter(

+ 8 - 4
netbox/ipam/filters.py

@@ -7,7 +7,7 @@ from netaddr.core import AddrFormatError
 from dcim.models import Site, Device, Interface
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from virtualization.models import VirtualMachine
 from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES
 from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
@@ -48,7 +48,7 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
         fields = ['name', 'rd', 'enforce_unique']
 
 
-class RIRFilter(django_filters.FilterSet):
+class RIRFilter(NameSlugSearchFilterSet):
     id__in = NumericInFilter(
         field_name='id',
         lookup_expr='in'
@@ -96,7 +96,11 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
         return queryset.filter(qs_filter)
 
 
-class RoleFilter(django_filters.FilterSet):
+class RoleFilter(NameSlugSearchFilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
 
     class Meta:
         model = Role
@@ -373,7 +377,7 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
             return queryset.none()
 
 
-class VLANGroupFilter(django_filters.FilterSet):
+class VLANGroupFilter(NameSlugSearchFilterSet):
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         label='Site (ID)',

+ 2 - 2
netbox/secrets/filters.py

@@ -3,11 +3,11 @@ from django.db.models import Q
 
 from dcim.models import Device
 from extras.filters import CustomFieldFilterSet
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from .models import Secret, SecretRole
 
 
-class SecretRoleFilter(django_filters.FilterSet):
+class SecretRoleFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = SecretRole

+ 2 - 2
netbox/tenancy/filters.py

@@ -2,11 +2,11 @@ import django_filters
 from django.db.models import Q
 
 from extras.filters import CustomFieldFilterSet
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from .models import Tenant, TenantGroup
 
 
-class TenantGroupFilter(django_filters.FilterSet):
+class TenantGroupFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = TenantGroup

+ 19 - 0
netbox/utilities/filters.py

@@ -1,4 +1,5 @@
 import django_filters
+from django.db.models import Q
 from taggit.models import Tag
 
 
@@ -35,3 +36,21 @@ class TagFilter(django_filters.ModelMultipleChoiceFilter):
         kwargs.setdefault('queryset', Tag.objects.all())
 
         super().__init__(*args, **kwargs)
+
+
+class NameSlugSearchFilterSet(django_filters.FilterSet):
+    """
+    A base class for adding the search method to models which only expose the `name` and `slug` fields
+    """
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
+
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        return queryset.filter(
+            Q(name__icontains=value) |
+            Q(slug__icontains=value)
+        )

+ 14 - 3
netbox/virtualization/filters.py

@@ -7,19 +7,19 @@ from netaddr.core import AddrFormatError
 from dcim.models import DeviceRole, Interface, Platform, Region, Site
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from .constants import VM_STATUS_CHOICES
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
-class ClusterTypeFilter(django_filters.FilterSet):
+class ClusterTypeFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = ClusterType
         fields = ['name', 'slug']
 
 
-class ClusterGroupFilter(django_filters.FilterSet):
+class ClusterGroupFilter(NameSlugSearchFilterSet):
 
     class Meta:
         model = ClusterGroup
@@ -196,6 +196,10 @@ class VirtualMachineFilter(CustomFieldFilterSet):
 
 
 class InterfaceFilter(django_filters.FilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine',
         queryset=VirtualMachine.objects.all(),
@@ -225,3 +229,10 @@ class InterfaceFilter(django_filters.FilterSet):
             return queryset.filter(mac_address=mac)
         except AddrFormatError:
             return queryset.none()
+
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        return queryset.filter(
+            Q(name__icontains=value)
+        )