Parcourir la source

Closes #927: Upgrade to django-filter 1.0

Jeremy Stretch il y a 8 ans
Parent
commit
1adae67dd7

+ 10 - 6
netbox/circuits/filters.py

@@ -11,8 +11,8 @@ from .models import Provider, Circuit, CircuitType
 
 
 class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
@@ -31,7 +31,9 @@ class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Provider
         fields = ['name', 'account', 'asn']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(account__icontains=value) |
@@ -40,8 +42,8 @@ class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
 
 class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     provider_id = django_filters.ModelMultipleChoiceFilter(
@@ -93,7 +95,9 @@ class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Circuit
         fields = ['install_date']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(cid__icontains=value) |
             Q(terminations__xconnect_id__icontains=value) |

+ 18 - 8
netbox/circuits/forms.py

@@ -64,6 +64,7 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Provider
     q = forms.CharField(required=False, label='Search')
     site = FilterChoiceField(queryset=Site.objects.all(), to_field_name='slug')
+    asn = forms.IntegerField(required=False, label='ASN')
 
 
 #
@@ -128,14 +129,23 @@ class CircuitBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Circuit
     q = forms.CharField(required=False, label='Search')
-    type = FilterChoiceField(queryset=CircuitType.objects.annotate(filter_count=Count('circuits')),
-                             to_field_name='slug')
-    provider = FilterChoiceField(queryset=Provider.objects.annotate(filter_count=Count('circuits')),
-                                 to_field_name='slug')
-    tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('circuits')), to_field_name='slug',
-                               null_option=(0, 'None'))
-    site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('circuit_terminations')),
-                             to_field_name='slug')
+    type = FilterChoiceField(
+        queryset=CircuitType.objects.annotate(filter_count=Count('circuits')),
+        to_field_name='slug'
+    )
+    provider = FilterChoiceField(
+        queryset=Provider.objects.annotate(filter_count=Count('circuits')),
+        to_field_name='slug'
+    )
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('circuits')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
+    site = FilterChoiceField(
+        queryset=Site.objects.annotate(filter_count=Count('circuit_terminations')),
+        to_field_name='slug'
+    )
 
 
 #

+ 56 - 41
netbox/dcim/filters.py

@@ -14,8 +14,8 @@ from .models import (
 
 
 class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     region_id = NullableModelMultipleChoiceFilter(
@@ -45,9 +45,16 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Site
         fields = ['q', 'name', 'facility', 'asn']
 
-    def search(self, queryset, value):
-        qs_filter = Q(name__icontains=value) | Q(facility__icontains=value) | Q(physical_address__icontains=value) | \
-            Q(shipping_address__icontains=value) | Q(comments__icontains=value)
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
+        qs_filter = (
+            Q(name__icontains=value) |
+            Q(facility__icontains=value) |
+            Q(physical_address__icontains=value) |
+            Q(shipping_address__icontains=value) |
+            Q(comments__icontains=value)
+        )
         try:
             qs_filter |= Q(asn=int(value.strip()))
         except ValueError:
@@ -70,11 +77,12 @@ class RackGroupFilter(django_filters.FilterSet):
 
     class Meta:
         model = RackGroup
+        fields = ['name']
 
 
 class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
@@ -126,7 +134,9 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Rack
         fields = ['u_height']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(facility_id__icontains=value) |
@@ -147,8 +157,8 @@ class RackReservationFilter(django_filters.FilterSet):
 
 
 class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     manufacturer_id = django_filters.ModelMultipleChoiceFilter(
@@ -165,10 +175,13 @@ class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = DeviceType
-        fields = ['model', 'part_number', 'u_height', 'is_console_server', 'is_pdu', 'is_network_device',
-                  'subdevice_role']
+        fields = [
+            'model', 'part_number', 'u_height', 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role',
+        ]
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(manufacturer__name__icontains=value) |
             Q(model__icontains=value) |
@@ -178,12 +191,12 @@ class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
 
 class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
-    mac_address = django_filters.MethodFilter(
-        action='_mac_address',
+    mac_address = django_filters.CharFilter(
+        method='_mac_address',
         label='MAC address',
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
@@ -283,7 +296,9 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Device
         fields = ['name', 'serial', 'asset_tag']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(serial__icontains=value.strip()) |
@@ -292,7 +307,7 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
             Q(comments__icontains=value)
         ).distinct()
 
-    def _mac_address(self, queryset, value):
+    def _mac_address(self, queryset, name, value):
         value = value.strip()
         if not value:
             return queryset
@@ -386,8 +401,8 @@ class InterfaceFilter(django_filters.FilterSet):
         to_field_name='name',
         label='Device (name)',
     )
-    type = django_filters.MethodFilter(
-        action='filter_type',
+    type = django_filters.CharFilter(
+        method='filter_type',
         label='Interface type',
     )
 
@@ -395,7 +410,7 @@ class InterfaceFilter(django_filters.FilterSet):
         model = Interface
         fields = ['name']
 
-    def filter_type(self, queryset, value):
+    def filter_type(self, queryset, name, value):
         value = value.strip().lower()
         if value == 'physical':
             return queryset.exclude(form_factor__in=VIRTUAL_IFACE_TYPES)
@@ -407,51 +422,51 @@ class InterfaceFilter(django_filters.FilterSet):
 
 
 class ConsoleConnectionFilter(django_filters.FilterSet):
-    site = django_filters.MethodFilter(
-        action='filter_site',
+    site = django_filters.CharFilter(
+        method='filter_site',
         label='Site (slug)',
     )
 
     class Meta:
         model = ConsoleServerPort
+        fields = []
 
-    def filter_site(self, queryset, value):
-        value = value.strip()
-        if not value:
+    def filter_site(self, queryset, name, value):
+        if not value.strip():
             return queryset
-        return queryset.filter(cs_port__device__rack__site__slug=value)
+        return queryset.filter(cs_port__device__site__slug=value)
 
 
 class PowerConnectionFilter(django_filters.FilterSet):
-    site = django_filters.MethodFilter(
-        action='filter_site',
+    site = django_filters.CharFilter(
+        method='filter_site',
         label='Site (slug)',
     )
 
     class Meta:
         model = PowerOutlet
+        fields = []
 
-    def filter_site(self, queryset, value):
-        value = value.strip()
-        if not value:
+    def filter_site(self, queryset, name, value):
+        if not value.strip():
             return queryset
-        return queryset.filter(power_outlet__device__rack__site__slug=value)
+        return queryset.filter(power_outlet__device__site__slug=value)
 
 
 class InterfaceConnectionFilter(django_filters.FilterSet):
-    site = django_filters.MethodFilter(
-        action='filter_site',
+    site = django_filters.CharFilter(
+        method='filter_site',
         label='Site (slug)',
     )
 
     class Meta:
         model = InterfaceConnection
+        fields = []
 
-    def filter_site(self, queryset, value):
-        value = value.strip()
-        if not value:
+    def filter_site(self, queryset, name, value):
+        if not value.strip():
             return queryset
         return queryset.filter(
-            Q(interface_a__device__rack__site__slug=value) |
-            Q(interface_b__device__rack__site__slug=value)
+            Q(interface_a__device__site__slug=value) |
+            Q(interface_b__device__site__slug=value)
         )

+ 24 - 10
netbox/dcim/forms.py

@@ -281,13 +281,25 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Rack
     q = forms.CharField(required=False, label='Search')
-    site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('racks')), to_field_name='slug')
-    group_id = FilterChoiceField(queryset=RackGroup.objects.select_related('site')
-                                 .annotate(filter_count=Count('racks')), label='Rack group', null_option=(0, 'None'))
-    tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('racks')), to_field_name='slug',
-                               null_option=(0, 'None'))
-    role = FilterChoiceField(queryset=RackRole.objects.annotate(filter_count=Count('racks')), to_field_name='slug',
-                             null_option=(0, 'None'))
+    site = FilterChoiceField(
+        queryset=Site.objects.annotate(filter_count=Count('racks')),
+        to_field_name='slug'
+    )
+    group_id = FilterChoiceField(
+        queryset=RackGroup.objects.select_related('site').annotate(filter_count=Count('racks')),
+        label='Rack group',
+        null_option=(0, 'None')
+    )
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('racks')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
+    role = FilterChoiceField(
+        queryset=RackRole.objects.annotate(filter_count=Count('racks')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
 
 
 #
@@ -359,8 +371,10 @@ class DeviceTypeBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = DeviceType
     q = forms.CharField(required=False, label='Search')
-    manufacturer = FilterChoiceField(queryset=Manufacturer.objects.annotate(filter_count=Count('device_types')),
-                                     to_field_name='slug')
+    manufacturer = FilterChoiceField(
+        queryset=Manufacturer.objects.annotate(filter_count=Count('device_types')),
+        to_field_name='slug'
+    )
 
 
 #
@@ -724,7 +738,7 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
     )
     rack_group_id = FilterChoiceField(
         queryset=RackGroup.objects.select_related('site').annotate(filter_count=Count('racks__devices')),
-        label='Rack Group',
+        label='Rack group',
     )
     role = FilterChoiceField(
         queryset=DeviceRole.objects.annotate(filter_count=Count('devices')),

+ 37 - 58
netbox/ipam/filters.py

@@ -13,15 +13,10 @@ from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLAN
 
 
 class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
-    name = django_filters.CharFilter(
-        name='name',
-        lookup_type='icontains',
-        label='Name',
-    )
     tenant_id = NullableModelMultipleChoiceFilter(
         name='tenant',
         queryset=Tenant.objects.all(),
@@ -34,7 +29,9 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
         label='Tenant (slug)',
     )
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(rd__icontains=value) |
@@ -43,7 +40,7 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = VRF
-        fields = ['rd']
+        fields = ['name', 'rd']
 
 
 class RIRFilter(django_filters.FilterSet):
@@ -54,8 +51,8 @@ class RIRFilter(django_filters.FilterSet):
 
 
 class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     rir_id = django_filters.ModelMultipleChoiceFilter(
@@ -74,7 +71,9 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Aggregate
         fields = ['family', 'date_added']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         qs_filter = Q(description__icontains=value)
         try:
             prefix = str(IPNetwork(value.strip()).cidr)
@@ -85,12 +84,12 @@ class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
 
 class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
-    parent = django_filters.MethodFilter(
-        action='search_by_parent',
+    parent = django_filters.CharFilter(
+        method='search_by_parent',
         label='Parent prefix',
     )
     vrf_id = NullableModelMultipleChoiceFilter(
@@ -151,7 +150,9 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
         model = Prefix
         fields = ['family', 'status']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         qs_filter = Q(description__icontains=value)
         try:
             prefix = str(IPNetwork(value.strip()).cidr)
@@ -160,7 +161,7 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
             pass
         return queryset.filter(qs_filter)
 
-    def search_by_parent(self, queryset, value):
+    def search_by_parent(self, queryset, name, value):
         value = value.strip()
         if not value:
             return queryset
@@ -170,32 +171,14 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
         except AddrFormatError:
             return queryset.none()
 
-    def _tenant(self, queryset, value):
-        if str(value) == '':
-            return queryset
-        return queryset.filter(
-            Q(tenant__slug=value) |
-            Q(tenant__isnull=True, vrf__tenant__slug=value)
-        )
-
-    def _tenant_id(self, queryset, value):
-        try:
-            value = int(value)
-        except ValueError:
-            return queryset.none()
-        return queryset.filter(
-            Q(tenant__pk=value) |
-            Q(tenant__isnull=True, vrf__tenant__pk=value)
-        )
-
 
 class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
-    parent = django_filters.MethodFilter(
-        action='search_by_parent',
+    parent = django_filters.CharFilter(
+        method='search_by_parent',
         label='Parent prefix',
     )
     vrf_id = NullableModelMultipleChoiceFilter(
@@ -239,9 +222,11 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = IPAddress
-        fields = ['q', 'family', 'status']
+        fields = ['family', 'status']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         qs_filter = Q(description__icontains=value)
         try:
             ipaddress = str(IPNetwork(value.strip()))
@@ -250,12 +235,12 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
             pass
         return queryset.filter(qs_filter)
 
-    def search_by_parent(self, queryset, value):
+    def search_by_parent(self, queryset, name, value):
         value = value.strip()
         if not value:
             return queryset
         try:
-            query = str(IPNetwork(value).cidr)
+            query = str(IPNetwork(value.strip()).cidr)
             return queryset.filter(address__net_contained_or_equal=query)
         except AddrFormatError:
             return queryset.none()
@@ -276,11 +261,12 @@ class VLANGroupFilter(django_filters.FilterSet):
 
     class Meta:
         model = VLANGroup
+        fields = ['name']
 
 
 class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     site_id = NullableModelMultipleChoiceFilter(
@@ -305,15 +291,6 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
         to_field_name='slug',
         label='Group',
     )
-    name = django_filters.CharFilter(
-        name='name',
-        lookup_type='icontains',
-        label='Name',
-    )
-    vid = django_filters.NumberFilter(
-        name='vid',
-        label='VLAN number (1-4095)',
-    )
     tenant_id = NullableModelMultipleChoiceFilter(
         name='tenant',
         queryset=Tenant.objects.all(),
@@ -339,12 +316,14 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = VLAN
-        fields = ['status']
+        fields = ['name', 'vid', 'status']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
         try:
-            qs_filter |= Q(vid=int(value))
+            qs_filter |= Q(vid=int(value.strip()))
         except ValueError:
             pass
         return queryset.filter(qs_filter)

+ 59 - 24
netbox/ipam/forms.py

@@ -131,8 +131,11 @@ class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Aggregate
     q = forms.CharField(required=False, label='Search')
     family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
-    rir = FilterChoiceField(queryset=RIR.objects.annotate(filter_count=Count('aggregates')), to_field_name='slug',
-                            label='RIR')
+    rir = FilterChoiceField(
+        queryset=RIR.objects.annotate(filter_count=Count('aggregates')),
+        to_field_name='slug',
+        label='RIR'
+    )
 
 
 #
@@ -259,19 +262,32 @@ def prefix_status_choices():
 class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Prefix
     q = forms.CharField(required=False, label='Search')
-    parent = forms.CharField(required=False, label='Parent Prefix', widget=forms.TextInput(attrs={
+    parent = forms.CharField(required=False, label='Parent prefix', widget=forms.TextInput(attrs={
         'placeholder': 'Prefix',
     }))
-    family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
-    vrf = FilterChoiceField(queryset=VRF.objects.annotate(filter_count=Count('prefixes')), to_field_name='rd',
-                            label='VRF', null_option=(0, 'Global'))
-    tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
-                               null_option=(0, 'None'))
+    family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address family')
+    vrf = FilterChoiceField(
+        queryset=VRF.objects.annotate(filter_count=Count('prefixes')),
+        to_field_name='rd',
+        label='VRF',
+        null_option=(0, 'Global')
+    )
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('prefixes')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
     status = forms.MultipleChoiceField(choices=prefix_status_choices, required=False)
-    site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
-                             null_option=(0, 'None'))
-    role = FilterChoiceField(queryset=Role.objects.annotate(filter_count=Count('prefixes')), to_field_name='slug',
-                             null_option=(0, 'None'))
+    site = FilterChoiceField(
+        queryset=Site.objects.annotate(filter_count=Count('prefixes')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
+    role = FilterChoiceField(
+        queryset=Role.objects.annotate(filter_count=Count('prefixes')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
     expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
 
 
@@ -488,10 +504,17 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
         'placeholder': 'Prefix',
     }))
     family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
-    vrf = FilterChoiceField(queryset=VRF.objects.annotate(filter_count=Count('ip_addresses')), to_field_name='rd',
-                            label='VRF', null_option=(0, 'Global'))
-    tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('ip_addresses')),
-                               to_field_name='slug', null_option=(0, 'None'))
+    vrf = FilterChoiceField(
+        queryset=VRF.objects.annotate(filter_count=Count('ip_addresses')),
+        to_field_name='rd',
+        label='VRF',
+        null_option=(0, 'Global')
+    )
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('ip_addresses')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
     status = forms.MultipleChoiceField(choices=ipaddress_status_choices, required=False)
 
 
@@ -603,15 +626,27 @@ def vlan_status_choices():
 class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = VLAN
     q = forms.CharField(required=False, label='Search')
-    site = FilterChoiceField(queryset=Site.objects.annotate(filter_count=Count('vlans')), to_field_name='slug',
-                             null_option=(0, 'Global'))
-    group_id = FilterChoiceField(queryset=VLANGroup.objects.annotate(filter_count=Count('vlans')), label='VLAN group',
-                                 null_option=(0, 'None'))
-    tenant = FilterChoiceField(queryset=Tenant.objects.annotate(filter_count=Count('vlans')), to_field_name='slug',
-                               null_option=(0, 'None'))
+    site = FilterChoiceField(
+        queryset=Site.objects.annotate(filter_count=Count('vlans')),
+        to_field_name='slug',
+        null_option=(0, 'Global')
+    )
+    group_id = FilterChoiceField(
+        queryset=VLANGroup.objects.annotate(filter_count=Count('vlans')),
+        label='VLAN group',
+        null_option=(0, 'None')
+    )
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('vlans')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
     status = forms.MultipleChoiceField(choices=vlan_status_choices, required=False)
-    role = FilterChoiceField(queryset=Role.objects.annotate(filter_count=Count('vlans')), to_field_name='slug',
-                             null_option=(0, 'None'))
+    role = FilterChoiceField(
+        queryset=Role.objects.annotate(filter_count=Count('vlans')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
 
 
 #

+ 5 - 3
netbox/secrets/filters.py

@@ -7,8 +7,8 @@ from dcim.models import Device
 
 
 class SecretFilter(django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     role_id = django_filters.ModelMultipleChoiceFilter(
@@ -33,7 +33,9 @@ class SecretFilter(django_filters.FilterSet):
         model = Secret
         fields = ['name']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(device__name__icontains=value)

+ 4 - 1
netbox/secrets/forms.py

@@ -101,7 +101,10 @@ class SecretBulkEditForm(BootstrapMixin, BulkEditForm):
 
 class SecretFilterForm(BootstrapMixin, forms.Form):
     q = forms.CharField(required=False, label='Search')
-    role = FilterChoiceField(queryset=SecretRole.objects.annotate(filter_count=Count('secrets')), to_field_name='slug')
+    role = FilterChoiceField(
+        queryset=SecretRole.objects.annotate(filter_count=Count('secrets')),
+        to_field_name='slug'
+    )
 
 
 #

+ 6 - 4
netbox/tenancy/filters.py

@@ -8,8 +8,8 @@ from .models import Tenant, TenantGroup
 
 
 class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
-    q = django_filters.MethodFilter(
-        action='search',
+    q = django_filters.CharFilter(
+        method='search',
         label='Search',
     )
     group_id = NullableModelMultipleChoiceFilter(
@@ -26,9 +26,11 @@ class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
 
     class Meta:
         model = Tenant
-        fields = ['q', 'group_id', 'group', 'name']
+        fields = ['name']
 
-    def search(self, queryset, value):
+    def search(self, queryset, name, value):
+        if not value.strip():
+            return queryset
         return queryset.filter(
             Q(name__icontains=value) |
             Q(description__icontains=value) |

+ 5 - 2
netbox/tenancy/forms.py

@@ -56,5 +56,8 @@ class TenantBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Tenant
     q = forms.CharField(required=False, label='Search')
-    group = FilterChoiceField(queryset=TenantGroup.objects.annotate(filter_count=Count('tenants')),
-                              to_field_name='slug', null_option=(0, 'None'))
+    group = FilterChoiceField(
+        queryset=TenantGroup.objects.annotate(filter_count=Count('tenants')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )

+ 1 - 1
requirements.txt

@@ -2,7 +2,7 @@ cffi>=1.8
 cryptography>=1.4
 Django>=1.10
 django-debug-toolbar>=1.6
-django-filter==0.15.3
+django-filter>=1.0.1
 django-mptt==0.8.7
 django-rest-swagger==0.3.10
 django-tables2>=1.2.5