mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 11:37:21 -06:00
Added 'none' options to filters for optional fields
This commit is contained in:
parent
daadf7a49b
commit
9dea5656ad
@ -5,6 +5,8 @@ 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 NullableModelMultipleChoiceFilter
|
||||||
|
|
||||||
from .models import Provider, Circuit, CircuitType
|
from .models import Provider, Circuit, CircuitType
|
||||||
|
|
||||||
|
|
||||||
@ -64,12 +66,12 @@ class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Circuit type (slug)',
|
label='Circuit type (slug)',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
@ -187,5 +187,6 @@ class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
model = Circuit
|
model = Circuit
|
||||||
type = FilterChoiceField(choices=get_filter_choices(CircuitType, id_field='slug', count_field='circuits'))
|
type = FilterChoiceField(choices=get_filter_choices(CircuitType, id_field='slug', count_field='circuits'))
|
||||||
provider = FilterChoiceField(choices=get_filter_choices(Provider, id_field='slug', count_field='circuits'))
|
provider = FilterChoiceField(choices=get_filter_choices(Provider, id_field='slug', count_field='circuits'))
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='circuits'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='circuits',
|
||||||
|
null_option='None'))
|
||||||
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='circuits'))
|
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='circuits'))
|
||||||
|
@ -4,6 +4,7 @@ from django.db.models import Q
|
|||||||
|
|
||||||
from extras.filters import CustomFieldFilterSet
|
from extras.filters import CustomFieldFilterSet
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
|
from utilities.filters import NullableModelMultipleChoiceFilter
|
||||||
from .models import (
|
from .models import (
|
||||||
ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, Interface, InterfaceConnection, Manufacturer,
|
ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, Interface, InterfaceConnection, Manufacturer,
|
||||||
Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site,
|
Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site,
|
||||||
@ -15,12 +16,12 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
action='search',
|
action='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -75,34 +76,34 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Site (slug)',
|
label='Site (slug)',
|
||||||
)
|
)
|
||||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
group_id = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=RackGroup.objects.all(),
|
queryset=RackGroup.objects.all(),
|
||||||
label='Group (ID)',
|
label='Group (ID)',
|
||||||
)
|
)
|
||||||
group = django_filters.ModelMultipleChoiceFilter(
|
group = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=RackGroup.objects.all(),
|
queryset=RackGroup.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Group',
|
label='Group',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Tenant (slug)',
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
role_id = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=RackRole.objects.all(),
|
queryset=RackRole.objects.all(),
|
||||||
label='Role (ID)',
|
label='Role (ID)',
|
||||||
)
|
)
|
||||||
role = django_filters.ModelMultipleChoiceFilter(
|
role = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=RackRole.objects.all(),
|
queryset=RackRole.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -177,12 +178,12 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Role (slug)',
|
label='Role (slug)',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -210,12 +211,12 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Device model (slug)',
|
label='Device model (slug)',
|
||||||
)
|
)
|
||||||
platform_id = django_filters.ModelMultipleChoiceFilter(
|
platform_id = NullableModelMultipleChoiceFilter(
|
||||||
name='platform',
|
name='platform',
|
||||||
queryset=Platform.objects.all(),
|
queryset=Platform.objects.all(),
|
||||||
label='Platform (ID)',
|
label='Platform (ID)',
|
||||||
)
|
)
|
||||||
platform = django_filters.ModelMultipleChoiceFilter(
|
platform = NullableModelMultipleChoiceFilter(
|
||||||
name='platform',
|
name='platform',
|
||||||
queryset=Platform.objects.all(),
|
queryset=Platform.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
@ -120,7 +120,8 @@ class SiteBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
|
|
||||||
class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = Site
|
model = Site
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='sites'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='sites',
|
||||||
|
null_option='None'))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -246,10 +247,13 @@ class RackBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = Rack
|
model = Rack
|
||||||
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='racks'))
|
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='racks'))
|
||||||
group_id = FilterChoiceField(choices=get_filter_choices(RackGroup, select_related=['site'], count_field='racks'),
|
group_id = FilterChoiceField(choices=get_filter_choices(RackGroup, select_related=['site'], count_field='racks',
|
||||||
|
null_option='None'),
|
||||||
label='Rack Group')
|
label='Rack Group')
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='racks'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='racks',
|
||||||
role = FilterChoiceField(choices=get_filter_choices(RackRole, id_field='slug', count_field='racks'))
|
null_option='None'))
|
||||||
|
role = FilterChoiceField(choices=get_filter_choices(RackRole, id_field='slug', count_field='racks',
|
||||||
|
null_option='None'))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -595,11 +599,13 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
count_field='racks__devices'),
|
count_field='racks__devices'),
|
||||||
label='Rack Group')
|
label='Rack Group')
|
||||||
role = FilterChoiceField(choices=get_filter_choices(DeviceRole, id_field='slug', count_field='devices'))
|
role = FilterChoiceField(choices=get_filter_choices(DeviceRole, id_field='slug', count_field='devices'))
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='devices'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='devices',
|
||||||
|
null_option='None'))
|
||||||
device_type_id = FilterChoiceField(choices=get_filter_choices(DeviceType, select_related=['manufacturer'],
|
device_type_id = FilterChoiceField(choices=get_filter_choices(DeviceType, select_related=['manufacturer'],
|
||||||
count_field='instances'),
|
count_field='instances'),
|
||||||
label='Type')
|
label='Type')
|
||||||
platform = FilterChoiceField(choices=get_filter_choices(Platform, id_field='slug', count_field='devices'))
|
platform = FilterChoiceField(choices=get_filter_choices(Platform, id_field='slug', count_field='devices',
|
||||||
|
null_option='None'))
|
||||||
status = forms.NullBooleanField(required=False, widget=forms.Select(choices=FORM_STATUS_CHOICES))
|
status = forms.NullBooleanField(required=False, widget=forms.Select(choices=FORM_STATUS_CHOICES))
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from django.db.models import Q
|
|||||||
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 NullableModelMultipleChoiceFilter
|
||||||
|
|
||||||
from .models import RIR, Aggregate, VRF, Prefix, IPAddress, VLAN, VLANGroup, Role
|
from .models import RIR, Aggregate, VRF, Prefix, IPAddress, VLAN, VLANGroup, Role
|
||||||
|
|
||||||
@ -21,12 +22,12 @@ class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
lookup_type='icontains',
|
lookup_type='icontains',
|
||||||
label='Name',
|
label='Name',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -85,29 +86,34 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
action='search_by_parent',
|
action='search_by_parent',
|
||||||
label='Parent prefix',
|
label='Parent prefix',
|
||||||
)
|
)
|
||||||
vrf = django_filters.MethodFilter(
|
vrf = NullableModelMultipleChoiceFilter(
|
||||||
action='_vrf',
|
name='vrf',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
label='VRF',
|
label='VRF',
|
||||||
)
|
)
|
||||||
# Duplicate of `vrf` for backward-compatibility
|
# Duplicate of `vrf` for backward-compatibility
|
||||||
vrf_id = django_filters.MethodFilter(
|
vrf_id = NullableModelMultipleChoiceFilter(
|
||||||
action='_vrf',
|
name='vrf_id',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
label='VRF',
|
label='VRF',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.MethodFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
action='_tenant_id',
|
name='tenant',
|
||||||
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.MethodFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
action='_tenant',
|
name='tenant',
|
||||||
label='Tenant',
|
queryset=Tenant.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
site_id = NullableModelMultipleChoiceFilter(
|
||||||
name='site',
|
name='site',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
label='Site (ID)',
|
label='Site (ID)',
|
||||||
)
|
)
|
||||||
site = django_filters.ModelMultipleChoiceFilter(
|
site = NullableModelMultipleChoiceFilter(
|
||||||
name='site',
|
name='site',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -122,12 +128,12 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
name='vlan__vid',
|
name='vlan__vid',
|
||||||
label='VLAN number (1-4095)',
|
label='VLAN number (1-4095)',
|
||||||
)
|
)
|
||||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
role_id = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=Role.objects.all(),
|
queryset=Role.objects.all(),
|
||||||
label='Role (ID)',
|
label='Role (ID)',
|
||||||
)
|
)
|
||||||
role = django_filters.ModelMultipleChoiceFilter(
|
role = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=Role.objects.all(),
|
queryset=Role.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -136,7 +142,7 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ['family', 'site_id', 'site', 'vrf', 'vrf_id', 'vlan_id', 'vlan_vid', 'status', 'role_id', 'role']
|
fields = ['family', 'site_id', 'site', 'vlan_id', 'vlan_vid', 'status', 'role_id', 'role']
|
||||||
|
|
||||||
def search(self, queryset, value):
|
def search(self, queryset, value):
|
||||||
qs_filter = Q(description__icontains=value)
|
qs_filter = Q(description__icontains=value)
|
||||||
@ -157,17 +163,6 @@ class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
except AddrFormatError:
|
except AddrFormatError:
|
||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
|
||||||
def _vrf(self, queryset, value):
|
|
||||||
if str(value) == '':
|
|
||||||
return queryset
|
|
||||||
try:
|
|
||||||
vrf_id = int(value)
|
|
||||||
except ValueError:
|
|
||||||
return queryset.none()
|
|
||||||
if vrf_id == 0:
|
|
||||||
return queryset.filter(vrf__isnull=True)
|
|
||||||
return queryset.filter(vrf__pk=value)
|
|
||||||
|
|
||||||
def _tenant(self, queryset, value):
|
def _tenant(self, queryset, value):
|
||||||
if str(value) == '':
|
if str(value) == '':
|
||||||
return queryset
|
return queryset
|
||||||
@ -196,22 +191,27 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
action='search_by_parent',
|
action='search_by_parent',
|
||||||
label='Parent prefix',
|
label='Parent prefix',
|
||||||
)
|
)
|
||||||
vrf = django_filters.MethodFilter(
|
vrf = NullableModelMultipleChoiceFilter(
|
||||||
action='_vrf',
|
name='vrf',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
label='VRF',
|
label='VRF',
|
||||||
)
|
)
|
||||||
# Duplicate of `vrf` for backward-compatibility
|
# Duplicate of `vrf` for backward-compatibility
|
||||||
vrf_id = django_filters.MethodFilter(
|
vrf_id = NullableModelMultipleChoiceFilter(
|
||||||
action='_vrf',
|
name='vrf_id',
|
||||||
|
queryset=VRF.objects.all(),
|
||||||
label='VRF',
|
label='VRF',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.MethodFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
action='_tenant_id',
|
name='tenant',
|
||||||
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.MethodFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
action='_tenant',
|
name='tenant',
|
||||||
label='Tenant',
|
queryset=Tenant.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
device_id = django_filters.ModelMultipleChoiceFilter(
|
device_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
name='interface__device',
|
name='interface__device',
|
||||||
@ -232,7 +232,7 @@ class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = ['q', 'family', 'vrf_id', 'vrf', 'device_id', 'device', 'interface_id']
|
fields = ['q', 'family', 'device_id', 'device', 'interface_id']
|
||||||
|
|
||||||
def search(self, queryset, value):
|
def search(self, queryset, value):
|
||||||
qs_filter = Q(description__icontains=value)
|
qs_filter = Q(description__icontains=value)
|
||||||
@ -317,12 +317,12 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Site (slug)',
|
label='Site (slug)',
|
||||||
)
|
)
|
||||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
group_id = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=VLANGroup.objects.all(),
|
queryset=VLANGroup.objects.all(),
|
||||||
label='Group (ID)',
|
label='Group (ID)',
|
||||||
)
|
)
|
||||||
group = django_filters.ModelMultipleChoiceFilter(
|
group = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=VLANGroup.objects.all(),
|
queryset=VLANGroup.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -337,23 +337,23 @@ class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
name='vid',
|
name='vid',
|
||||||
label='VLAN number (1-4095)',
|
label='VLAN number (1-4095)',
|
||||||
)
|
)
|
||||||
tenant_id = django_filters.ModelMultipleChoiceFilter(
|
tenant_id = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
label='Tenant (ID)',
|
label='Tenant (ID)',
|
||||||
)
|
)
|
||||||
tenant = django_filters.ModelMultipleChoiceFilter(
|
tenant = NullableModelMultipleChoiceFilter(
|
||||||
name='tenant',
|
name='tenant',
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Tenant (slug)',
|
label='Tenant (slug)',
|
||||||
)
|
)
|
||||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
role_id = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=Role.objects.all(),
|
queryset=Role.objects.all(),
|
||||||
label='Role (ID)',
|
label='Role (ID)',
|
||||||
)
|
)
|
||||||
role = django_filters.ModelMultipleChoiceFilter(
|
role = NullableModelMultipleChoiceFilter(
|
||||||
name='role',
|
name='role',
|
||||||
queryset=Role.objects.all(),
|
queryset=Role.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
@ -74,7 +74,8 @@ class VRFBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
|
|
||||||
class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = VRF
|
model = VRF
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vrfs'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vrfs',
|
||||||
|
null_option='None'))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -272,13 +273,16 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
'placeholder': 'Network',
|
'placeholder': 'Network',
|
||||||
}))
|
}))
|
||||||
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
|
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
|
||||||
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='prefixes', null_option=(0, 'Global')),
|
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='prefixes', null_option='Global'),
|
||||||
label='VRF')
|
label='VRF')
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='prefixes'),
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='prefixes',
|
||||||
|
null_option='None'),
|
||||||
label='Tenant')
|
label='Tenant')
|
||||||
status = FilterChoiceField(choices=prefix_status_choices)
|
status = FilterChoiceField(choices=prefix_status_choices)
|
||||||
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='prefixes'))
|
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='prefixes',
|
||||||
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='prefixes'))
|
null_option='None'))
|
||||||
|
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='prefixes',
|
||||||
|
null_option='None'))
|
||||||
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
|
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
|
||||||
|
|
||||||
|
|
||||||
@ -415,8 +419,10 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
'placeholder': 'Prefix',
|
'placeholder': 'Prefix',
|
||||||
}))
|
}))
|
||||||
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
|
family = forms.ChoiceField(required=False, choices=IP_FAMILY_CHOICES, label='Address Family')
|
||||||
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='ip_addresses'), label='VRF')
|
vrf = FilterChoiceField(choices=get_filter_choices(VRF, count_field='ip_addresses', null_option='None'),
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='prefixes'),
|
label='VRF')
|
||||||
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='ip_addresses',
|
||||||
|
null_option='None'),
|
||||||
label='Tenant')
|
label='Tenant')
|
||||||
|
|
||||||
|
|
||||||
@ -521,8 +527,10 @@ def vlan_status_choices():
|
|||||||
class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = VLAN
|
model = VLAN
|
||||||
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='vlans'))
|
site = FilterChoiceField(choices=get_filter_choices(Site, id_field='slug', count_field='vlans'))
|
||||||
group_id = FilterChoiceField(choices=get_filter_choices(VLANGroup, select_related=['site'], count_field='vlans'),
|
group_id = FilterChoiceField(choices=get_filter_choices(VLANGroup, select_related=['site'], count_field='vlans',
|
||||||
|
null_option='None'),
|
||||||
label='VLAN Group')
|
label='VLAN Group')
|
||||||
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vlans'))
|
tenant = FilterChoiceField(choices=get_filter_choices(Tenant, id_field='slug', count_field='vlans',
|
||||||
|
null_option='None'))
|
||||||
status = FilterChoiceField(choices=vlan_status_choices)
|
status = FilterChoiceField(choices=vlan_status_choices)
|
||||||
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='vlans'))
|
role = FilterChoiceField(choices=get_filter_choices(Role, id_field='slug', count_field='vlans', null_option='None'))
|
||||||
|
@ -3,6 +3,7 @@ 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 NullableModelMultipleChoiceFilter
|
||||||
from .models import Tenant, TenantGroup
|
from .models import Tenant, TenantGroup
|
||||||
|
|
||||||
|
|
||||||
@ -11,12 +12,12 @@ class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet):
|
|||||||
action='search',
|
action='search',
|
||||||
label='Search',
|
label='Search',
|
||||||
)
|
)
|
||||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
group_id = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=TenantGroup.objects.all(),
|
queryset=TenantGroup.objects.all(),
|
||||||
label='Group (ID)',
|
label='Group (ID)',
|
||||||
)
|
)
|
||||||
group = django_filters.ModelMultipleChoiceFilter(
|
group = NullableModelMultipleChoiceFilter(
|
||||||
name='group',
|
name='group',
|
||||||
queryset=TenantGroup.objects.all(),
|
queryset=TenantGroup.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
@ -77,4 +77,5 @@ class TenantBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||||||
|
|
||||||
class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
model = Tenant
|
model = Tenant
|
||||||
group = FilterChoiceField(choices=get_filter_choices(TenantGroup, id_field='slug', count_field='tenants'))
|
group = FilterChoiceField(choices=get_filter_choices(TenantGroup, id_field='slug', count_field='tenants',
|
||||||
|
null_option='None'))
|
||||||
|
43
netbox/utilities/filters.py
Normal file
43
netbox/utilities/filters.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import django_filters
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
|
class NullableModelMultipleChoiceFilter(django_filters.MultipleChoiceFilter):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# Convert the queryset to a list of choices prefixed with a "None" option
|
||||||
|
queryset = kwargs.pop('queryset')
|
||||||
|
self.to_field_name = kwargs.pop('to_field_name', 'pk')
|
||||||
|
kwargs['choices'] = [(0, 'None')] + [(getattr(o, self.to_field_name), o) for o in queryset]
|
||||||
|
super(NullableModelMultipleChoiceFilter, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def filter(self, qs, value):
|
||||||
|
value = value or () # Make sure we have an iterable
|
||||||
|
|
||||||
|
if self.is_noop(qs, value):
|
||||||
|
return qs
|
||||||
|
|
||||||
|
# Even though not a noop, no point filtering if empty
|
||||||
|
if not value:
|
||||||
|
return qs
|
||||||
|
|
||||||
|
q = Q()
|
||||||
|
for v in set(value):
|
||||||
|
# Filtering on NULL
|
||||||
|
if v == str(0):
|
||||||
|
arg = {'{}__isnull'.format(self.name): True}
|
||||||
|
# Filtering on a related field (e.g. slug)
|
||||||
|
elif self.to_field_name != 'pk':
|
||||||
|
arg = {'{}__{}'.format(self.name, self.to_field_name): v}
|
||||||
|
# Filtering on primary key
|
||||||
|
else:
|
||||||
|
arg = {self.name: v}
|
||||||
|
if self.conjoined:
|
||||||
|
qs = self.get_method(qs)(**arg)
|
||||||
|
else:
|
||||||
|
q |= Q(**arg)
|
||||||
|
if self.distinct:
|
||||||
|
return self.get_method(qs)(q).distinct()
|
||||||
|
|
||||||
|
return self.get_method(qs)(q)
|
@ -43,7 +43,7 @@ def get_filter_choices(model, id_field='pk', select_related=[], count_field=None
|
|||||||
:param id_field: Field to use as the object identifier
|
:param id_field: Field to use as the object identifier
|
||||||
:param select_related: Any related tables to include
|
:param select_related: Any related tables to include
|
||||||
:param count_field: The field to use for a child COUNT() (optional)
|
:param count_field: The field to use for a child COUNT() (optional)
|
||||||
:param null_option: A (value, label) tuple to include at the beginning of the list serving as "null"
|
:param null_option: A choice to include at the beginning of the list serving as "null"
|
||||||
"""
|
"""
|
||||||
queryset = model.objects.all()
|
queryset = model.objects.all()
|
||||||
if select_related:
|
if select_related:
|
||||||
@ -54,7 +54,7 @@ def get_filter_choices(model, id_field='pk', select_related=[], count_field=None
|
|||||||
else:
|
else:
|
||||||
choices = [(getattr(obj, id_field), u'{}'.format(obj)) for obj in queryset]
|
choices = [(getattr(obj, id_field), u'{}'.format(obj)) for obj in queryset]
|
||||||
if null_option:
|
if null_option:
|
||||||
choices = [null_option] + choices
|
choices = [(0, null_option)] + choices
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user