From 1adae67dd7c5438dc1de159c8a9c1617a44872f2 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 1 Mar 2017 13:09:19 -0500 Subject: [PATCH] Closes #927: Upgrade to django-filter 1.0 --- netbox/circuits/filters.py | 16 ++++--- netbox/circuits/forms.py | 26 ++++++---- netbox/dcim/filters.py | 97 ++++++++++++++++++++++---------------- netbox/dcim/forms.py | 34 +++++++++---- netbox/ipam/filters.py | 95 +++++++++++++++---------------------- netbox/ipam/forms.py | 83 ++++++++++++++++++++++---------- netbox/secrets/filters.py | 8 ++-- netbox/secrets/forms.py | 5 +- netbox/tenancy/filters.py | 10 ++-- netbox/tenancy/forms.py | 7 ++- requirements.txt | 2 +- 11 files changed, 225 insertions(+), 158 deletions(-) diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index fa57a74dc..b07e87068 100644 --- a/netbox/circuits/filters.py +++ b/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) | diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 036b74810..940ae939a 100644 --- a/netbox/circuits/forms.py +++ b/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' + ) # diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 3360d8149..eca792a12 100644 --- a/netbox/dcim/filters.py +++ b/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) ) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index da9b2411b..1bcaa7a63 100644 --- a/netbox/dcim/forms.py +++ b/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')), diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index b83228f9c..3ed401417 100644 --- a/netbox/ipam/filters.py +++ b/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) diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 123ca0131..dd215fb16 100644 --- a/netbox/ipam/forms.py +++ b/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') + ) # diff --git a/netbox/secrets/filters.py b/netbox/secrets/filters.py index af6f62fbd..5f59daad4 100644 --- a/netbox/secrets/filters.py +++ b/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) diff --git a/netbox/secrets/forms.py b/netbox/secrets/forms.py index b4c64b485..2e08b0b22 100644 --- a/netbox/secrets/forms.py +++ b/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' + ) # diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 6eeeb1e7b..ed1721102 100644 --- a/netbox/tenancy/filters.py +++ b/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) | diff --git a/netbox/tenancy/forms.py b/netbox/tenancy/forms.py index 0e29a8495..485f2f34b 100644 --- a/netbox/tenancy/forms.py +++ b/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') + ) diff --git a/requirements.txt b/requirements.txt index 2d1c81ffa..2c6044f73 100644 --- a/requirements.txt +++ b/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