Explorar el Código

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

John Anderson hace 7 años
padre
commit
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
 * [#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
 * [#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 dcim.models import Site
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 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 .constants import CIRCUIT_STATUS_CHOICES
 from .models import Provider, Circuit, CircuitTermination, CircuitType
 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:
     class Meta:
         model = CircuitType
         model = CircuitType

+ 19 - 34
netbox/dcim/filters.py

@@ -8,7 +8,7 @@ from netaddr.core import AddrFormatError
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.constants import COLOR_CHOICES
 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 virtualization.models import Cluster
 from .constants import *
 from .constants import *
 from .models 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(
     parent_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         label='Parent region (ID)',
         label='Parent region (ID)',
@@ -39,15 +35,6 @@ class RegionFilter(django_filters.FilterSet):
         model = Region
         model = Region
         fields = ['name', 'slug']
         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):
 class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
     id__in = NumericInFilter(
     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(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         label='Site (ID)',
         label='Site (ID)',
@@ -139,17 +122,8 @@ class RackGroupFilter(django_filters.FilterSet):
         model = RackGroup
         model = RackGroup
         fields = ['site_id', 'name', 'slug']
         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:
     class Meta:
         model = RackRole
         model = RackRole
@@ -303,7 +277,7 @@ class RackReservationFilter(django_filters.FilterSet):
         )
         )
 
 
 
 
-class ManufacturerFilter(django_filters.FilterSet):
+class ManufacturerFilter(NameSlugSearchFilterSet):
 
 
     class Meta:
     class Meta:
         model = Manufacturer
         model = Manufacturer
@@ -393,7 +367,7 @@ class DeviceTypeFilter(CustomFieldFilterSet):
         )
         )
 
 
 
 
-class DeviceTypeComponentFilterSet(django_filters.FilterSet):
+class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet):
     devicetype_id = django_filters.ModelMultipleChoiceFilter(
     devicetype_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),
         field_name='device_type_id',
         field_name='device_type_id',
@@ -457,14 +431,14 @@ class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
         fields = ['name']
         fields = ['name']
 
 
 
 
-class DeviceRoleFilter(django_filters.FilterSet):
+class DeviceRoleFilter(NameSlugSearchFilterSet):
 
 
     class Meta:
     class Meta:
         model = DeviceRole
         model = DeviceRole
         fields = ['name', 'slug', 'color', 'vm_role']
         fields = ['name', 'slug', 'color', 'vm_role']
 
 
 
 
-class PlatformFilter(django_filters.FilterSet):
+class PlatformFilter(NameSlugSearchFilterSet):
     manufacturer_id = django_filters.ModelMultipleChoiceFilter(
     manufacturer_id = django_filters.ModelMultipleChoiceFilter(
         field_name='manufacturer',
         field_name='manufacturer',
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
@@ -696,6 +670,10 @@ class DeviceFilter(CustomFieldFilterSet):
 
 
 
 
 class DeviceComponentFilterSet(django_filters.FilterSet):
 class DeviceComponentFilterSet(django_filters.FilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
     device_id = django_filters.ModelChoiceFilter(
     device_id = django_filters.ModelChoiceFilter(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         label='Device (ID)',
         label='Device (ID)',
@@ -707,6 +685,13 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
     )
     )
     tag = TagFilter()
     tag = TagFilter()
 
 
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        return queryset.filter(
+            Q(name__icontains=value)
+        )
+
 
 
 class ConsolePortFilter(DeviceComponentFilterSet):
 class ConsolePortFilter(DeviceComponentFilterSet):
     cabled = django_filters.BooleanFilter(
     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 dcim.models import Site, Device, Interface
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 from tenancy.models import Tenant
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
 from .constants import IPADDRESS_ROLE_CHOICES, IPADDRESS_STATUS_CHOICES, PREFIX_STATUS_CHOICES, VLAN_STATUS_CHOICES
 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
 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']
         fields = ['name', 'rd', 'enforce_unique']
 
 
 
 
-class RIRFilter(django_filters.FilterSet):
+class RIRFilter(NameSlugSearchFilterSet):
     id__in = NumericInFilter(
     id__in = NumericInFilter(
         field_name='id',
         field_name='id',
         lookup_expr='in'
         lookup_expr='in'
@@ -96,7 +96,11 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
         return queryset.filter(qs_filter)
         return queryset.filter(qs_filter)
 
 
 
 
-class RoleFilter(django_filters.FilterSet):
+class RoleFilter(NameSlugSearchFilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
 
 
     class Meta:
     class Meta:
         model = Role
         model = Role
@@ -373,7 +377,7 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
             return queryset.none()
             return queryset.none()
 
 
 
 
-class VLANGroupFilter(django_filters.FilterSet):
+class VLANGroupFilter(NameSlugSearchFilterSet):
     site_id = django_filters.ModelMultipleChoiceFilter(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         label='Site (ID)',
         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 dcim.models import Device
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
-from utilities.filters import NumericInFilter, TagFilter
+from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter
 from .models import Secret, SecretRole
 from .models import Secret, SecretRole
 
 
 
 
-class SecretRoleFilter(django_filters.FilterSet):
+class SecretRoleFilter(NameSlugSearchFilterSet):
 
 
     class Meta:
     class Meta:
         model = SecretRole
         model = SecretRole

+ 2 - 2
netbox/tenancy/filters.py

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

+ 19 - 0
netbox/utilities/filters.py

@@ -1,4 +1,5 @@
 import django_filters
 import django_filters
+from django.db.models import Q
 from taggit.models import Tag
 from taggit.models import Tag
 
 
 
 
@@ -35,3 +36,21 @@ class TagFilter(django_filters.ModelMultipleChoiceFilter):
         kwargs.setdefault('queryset', Tag.objects.all())
         kwargs.setdefault('queryset', Tag.objects.all())
 
 
         super().__init__(*args, **kwargs)
         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 dcim.models import DeviceRole, Interface, Platform, Region, Site
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 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 .constants import VM_STATUS_CHOICES
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
 
 
 
 
-class ClusterTypeFilter(django_filters.FilterSet):
+class ClusterTypeFilter(NameSlugSearchFilterSet):
 
 
     class Meta:
     class Meta:
         model = ClusterType
         model = ClusterType
         fields = ['name', 'slug']
         fields = ['name', 'slug']
 
 
 
 
-class ClusterGroupFilter(django_filters.FilterSet):
+class ClusterGroupFilter(NameSlugSearchFilterSet):
 
 
     class Meta:
     class Meta:
         model = ClusterGroup
         model = ClusterGroup
@@ -196,6 +196,10 @@ class VirtualMachineFilter(CustomFieldFilterSet):
 
 
 
 
 class InterfaceFilter(django_filters.FilterSet):
 class InterfaceFilter(django_filters.FilterSet):
+    q = django_filters.CharFilter(
+        method='search',
+        label='Search',
+    )
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine',
         field_name='virtual_machine',
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
@@ -225,3 +229,10 @@ class InterfaceFilter(django_filters.FilterSet):
             return queryset.filter(mac_address=mac)
             return queryset.filter(mac_address=mac)
         except AddrFormatError:
         except AddrFormatError:
             return queryset.none()
             return queryset.none()
+
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        return queryset.filter(
+            Q(name__icontains=value)
+        )