From 1190adde2bd6bb121d8be28b9f60a31fadb6834e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Feb 2026 06:31:36 -0500 Subject: [PATCH] Closes #21419: Improve query efficiency for MultipleChoiceFilter (#21421) * Pass distinct=False to all ModelMultipleChoiceFilters associated with a ForeignKey field * Pass distinct=False to all MultipleChoiceFilters associated with a concrete model --- netbox/circuits/filtersets.py | 37 ++++++ netbox/core/filtersets.py | 12 +- netbox/dcim/base_filtersets.py | 2 + netbox/dcim/filtersets.py | 199 +++++++++++++++++++++++++--- netbox/extras/filtersets.py | 45 ++++++- netbox/ipam/filtersets.py | 50 ++++++- netbox/tenancy/filtersets.py | 9 ++ netbox/users/filterset_mixins.py | 4 + netbox/users/filtersets.py | 4 + netbox/virtualization/filtersets.py | 28 ++++ netbox/vpn/filtersets.py | 55 ++++++-- netbox/wireless/filtersets.py | 31 +++-- 12 files changed, 423 insertions(+), 53 deletions(-) diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index 3335e77a9..e41390909 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -99,11 +99,13 @@ class ProviderFilterSet(PrimaryModelFilterSet, ContactModelFilterSet): class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) @@ -127,11 +129,13 @@ class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet): class ProviderNetworkFilterSet(PrimaryModelFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) @@ -163,22 +167,26 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet): class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) provider_account_id = django_filters.ModelMultipleChoiceFilter( field_name='provider_account', queryset=ProviderAccount.objects.all(), + distinct=False, label=_('Provider account (ID)'), ) provider_account = django_filters.ModelMultipleChoiceFilter( field_name='provider_account__account', queryset=Provider.objects.all(), + distinct=False, to_field_name='account', label=_('Provider account (account)'), ) @@ -189,16 +197,19 @@ class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt ) type_id = django_filters.ModelMultipleChoiceFilter( queryset=CircuitType.objects.all(), + distinct=False, label=_('Circuit type (ID)'), ) type = django_filters.ModelMultipleChoiceFilter( field_name='type__slug', queryset=CircuitType.objects.all(), + distinct=False, to_field_name='slug', label=_('Circuit type (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=CircuitStatusChoices, + distinct=False, null_value=None ) region_id = TreeNodeMultipleChoiceFilter( @@ -245,10 +256,12 @@ class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt ) termination_a_id = django_filters.ModelMultipleChoiceFilter( queryset=CircuitTermination.objects.all(), + distinct=False, label=_('Termination A (ID)'), ) termination_z_id = django_filters.ModelMultipleChoiceFilter( queryset=CircuitTermination.objects.all(), + distinct=False, label=_('Termination A (ID)'), ) @@ -279,6 +292,7 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): ) circuit_id = django_filters.ModelMultipleChoiceFilter( queryset=Circuit.objects.all(), + distinct=False, label=_('Circuit'), ) termination_type = MultiValueContentTypeFilter() @@ -310,12 +324,14 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, field_name='_site', label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='_site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) @@ -334,17 +350,20 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): ) provider_network_id = django_filters.ModelMultipleChoiceFilter( queryset=ProviderNetwork.objects.all(), + distinct=False, field_name='_provider_network', label=_('ProviderNetwork (ID)'), ) provider_id = django_filters.ModelMultipleChoiceFilter( field_name='circuit__provider_id', queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='circuit__provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) @@ -414,11 +433,13 @@ class CircuitGroupAssignmentFilterSet(NetBoxModelFilterSet): ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=CircuitGroup.objects.all(), + distinct=False, label=_('Circuit group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=CircuitGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Circuit group (slug)'), ) @@ -488,41 +509,49 @@ class VirtualCircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( field_name='provider_network__provider', queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider_network__provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) provider_account_id = django_filters.ModelMultipleChoiceFilter( field_name='provider_account', queryset=ProviderAccount.objects.all(), + distinct=False, label=_('Provider account (ID)'), ) provider_account = django_filters.ModelMultipleChoiceFilter( field_name='provider_account__account', queryset=Provider.objects.all(), + distinct=False, to_field_name='account', label=_('Provider account (account)'), ) provider_network_id = django_filters.ModelMultipleChoiceFilter( queryset=ProviderNetwork.objects.all(), + distinct=False, label=_('Provider network (ID)'), ) type_id = django_filters.ModelMultipleChoiceFilter( queryset=VirtualCircuitType.objects.all(), + distinct=False, label=_('Virtual circuit type (ID)'), ) type = django_filters.ModelMultipleChoiceFilter( field_name='type__slug', queryset=VirtualCircuitType.objects.all(), + distinct=False, to_field_name='slug', label=_('Virtual circuit type (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=CircuitStatusChoices, + distinct=False, null_value=None ) @@ -548,41 +577,49 @@ class VirtualCircuitTerminationFilterSet(NetBoxModelFilterSet): ) virtual_circuit_id = django_filters.ModelMultipleChoiceFilter( queryset=VirtualCircuit.objects.all(), + distinct=False, label=_('Virtual circuit'), ) role = django_filters.MultipleChoiceFilter( choices=VirtualCircuitTerminationRoleChoices, + distinct=False, null_value=None ) provider_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_circuit__provider_network__provider', queryset=Provider.objects.all(), + distinct=False, label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='virtual_circuit__provider_network__provider__slug', queryset=Provider.objects.all(), + distinct=False, to_field_name='slug', label=_('Provider (slug)'), ) provider_account_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_circuit__provider_account', queryset=ProviderAccount.objects.all(), + distinct=False, label=_('Provider account (ID)'), ) provider_account = django_filters.ModelMultipleChoiceFilter( field_name='virtual_circuit__provider_account__account', queryset=ProviderAccount.objects.all(), + distinct=False, to_field_name='account', label=_('Provider account (account)'), ) provider_network_id = django_filters.ModelMultipleChoiceFilter( queryset=ProviderNetwork.objects.all(), + distinct=False, field_name='virtual_circuit__provider_network', label=_('Provider network (ID)'), ) interface_id = django_filters.ModelMultipleChoiceFilter( queryset=Interface.objects.all(), + distinct=False, field_name='interface', label=_('Interface (ID)'), ) diff --git a/netbox/core/filtersets.py b/netbox/core/filtersets.py index 3d391bd97..06f5748e4 100644 --- a/netbox/core/filtersets.py +++ b/netbox/core/filtersets.py @@ -25,14 +25,17 @@ __all__ = ( class DataSourceFilterSet(PrimaryModelFilterSet): type = django_filters.MultipleChoiceFilter( choices=get_data_backend_choices, + distinct=False, null_value=None ) status = django_filters.MultipleChoiceFilter( choices=DataSourceStatusChoices, + distinct=False, null_value=None ) sync_interval = django_filters.MultipleChoiceFilter( choices=JobIntervalChoices, + distinct=False, null_value=None ) @@ -57,11 +60,13 @@ class DataFileFilterSet(ChangeLoggedModelFilterSet): ) source_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data source (ID)'), ) source = django_filters.ModelMultipleChoiceFilter( field_name='source__name', queryset=DataSource.objects.all(), + distinct=False, to_field_name='name', label=_('Data source (name)'), ) @@ -86,6 +91,7 @@ class JobFilterSet(BaseFilterSet): ) object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ObjectType.objects.with_feature('jobs'), + distinct=False, field_name='object_type_id', ) object_type = MultiValueContentTypeFilter() @@ -127,6 +133,7 @@ class JobFilterSet(BaseFilterSet): ) status = django_filters.MultipleChoiceFilter( choices=JobStatusChoices, + distinct=False, null_value=None ) queue_name = django_filters.CharFilter() @@ -182,16 +189,19 @@ class ObjectChangeFilterSet(BaseFilterSet): time = django_filters.DateTimeFromToRangeFilter() changed_object_type = MultiValueContentTypeFilter() changed_object_type_id = django_filters.ModelMultipleChoiceFilter( - queryset=ContentType.objects.all() + queryset=ContentType.objects.all(), + distinct=False, ) related_object_type = MultiValueContentTypeFilter() user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User name'), ) diff --git a/netbox/dcim/base_filtersets.py b/netbox/dcim/base_filtersets.py index 68ad1b5d4..2343d1899 100644 --- a/netbox/dcim/base_filtersets.py +++ b/netbox/dcim/base_filtersets.py @@ -43,12 +43,14 @@ class ScopedFilterSet(BaseFilterSet): ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, field_name='_site', label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='_site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 5554732a3..228fb44ec 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -91,11 +91,13 @@ __all__ = ( class RegionFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Region.objects.all(), + distinct=False, label=_('Parent region (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=Region.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent region (slug)'), ) @@ -122,11 +124,13 @@ class RegionFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): class SiteGroupFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=SiteGroup.objects.all(), + distinct=False, label=_('Parent site group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=SiteGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent site group (slug)'), ) @@ -153,6 +157,7 @@ class SiteGroupFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet): class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet): status = django_filters.MultipleChoiceFilter( choices=SiteStatusChoices, + distinct=False, null_value=None ) region_id = TreeNodeMultipleChoiceFilter( @@ -244,21 +249,25 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, NestedGroupMode ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Location.objects.all(), + distinct=False, label=_('Parent location (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=Location.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent location (slug)'), ) @@ -277,6 +286,7 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, NestedGroupMode ) status = django_filters.MultipleChoiceFilter( choices=LocationStatusChoices, + distinct=False, null_value=None ) @@ -306,19 +316,23 @@ class RackRoleFilterSet(OrganizationalModelFilterSet): class RackTypeFilterSet(PrimaryModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) form_factor = django_filters.MultipleChoiceFilter( - choices=RackFormFactorChoices + choices=RackFormFactorChoices, + distinct=False, ) width = django_filters.MultipleChoiceFilter( - choices=RackWidthChoices + choices=RackWidthChoices, + distinct=False, ) class Meta: @@ -371,11 +385,13 @@ class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterS ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) @@ -395,41 +411,50 @@ class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterS manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='rack_type__manufacturer', queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='rack_type__manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) rack_type = django_filters.ModelMultipleChoiceFilter( field_name='rack_type__slug', queryset=RackType.objects.all(), + distinct=False, to_field_name='slug', label=_('Rack type (slug)'), ) rack_type_id = django_filters.ModelMultipleChoiceFilter( queryset=RackType.objects.all(), + distinct=False, label=_('Rack type (ID)'), ) status = django_filters.MultipleChoiceFilter( choices=RackStatusChoices, + distinct=False, null_value=None ) form_factor = django_filters.MultipleChoiceFilter( - choices=RackFormFactorChoices + choices=RackFormFactorChoices, + distinct=False, ) width = django_filters.MultipleChoiceFilter( - choices=RackWidthChoices + choices=RackWidthChoices, + distinct=False, ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=RackRole.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=RackRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) @@ -462,16 +487,19 @@ class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterS class RackReservationFilterSet(PrimaryModelFilterSet, TenancyFilterSet): rack_id = django_filters.ModelMultipleChoiceFilter( queryset=Rack.objects.all(), + distinct=False, label=_('Rack (ID)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='rack__site', queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='rack__site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) @@ -516,15 +544,18 @@ class RackReservationFilterSet(PrimaryModelFilterSet, TenancyFilterSet): ) status = django_filters.MultipleChoiceFilter( choices=RackReservationStatusChoices, + distinct=False, null_value=None ) user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) @@ -560,11 +591,13 @@ class ManufacturerFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet) class DeviceTypeFilterSet(PrimaryModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) @@ -721,21 +754,25 @@ class ModuleTypeProfileFilterSet(PrimaryModelFilterSet): class ModuleTypeFilterSet(AttributeFiltersMixin, PrimaryModelFilterSet): profile_id = django_filters.ModelMultipleChoiceFilter( queryset=ModuleTypeProfile.objects.all(), + distinct=False, label=_('Profile (ID)'), ) profile = django_filters.ModelMultipleChoiceFilter( field_name='profile__name', queryset=ModuleTypeProfile.objects.all(), + distinct=False, to_field_name='name', label=_('Profile (name)'), ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) @@ -813,6 +850,7 @@ class DeviceTypeComponentFilterSet(django_filters.FilterSet): ) device_type_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), + distinct=False, field_name='device_type_id', label=_('Device type (ID)'), ) @@ -829,6 +867,7 @@ class DeviceTypeComponentFilterSet(django_filters.FilterSet): class ModularDeviceTypeComponentFilterSet(DeviceTypeComponentFilterSet): module_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ModuleType.objects.all(), + distinct=False, field_name='module_type_id', label=_('Module type (ID)'), ) @@ -862,10 +901,12 @@ class PowerPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet): feed_leg = django_filters.MultipleChoiceFilter( choices=PowerOutletFeedLegChoices, + distinct=False, null_value=None ) power_port_id = django_filters.ModelMultipleChoiceFilter( queryset=PowerPortTemplate.objects.all(), + distinct=False, label=_('Power port (ID)'), ) @@ -878,20 +919,25 @@ class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceType class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=InterfaceTypeChoices, + distinct=False, null_value=None ) bridge_id = django_filters.ModelMultipleChoiceFilter( field_name='bridge', - queryset=InterfaceTemplate.objects.all() + queryset=InterfaceTemplate.objects.all(), + distinct=False, ) poe_mode = django_filters.MultipleChoiceFilter( - choices=InterfacePoEModeChoices + choices=InterfacePoEModeChoices, + distinct=False, ) poe_type = django_filters.MultipleChoiceFilter( - choices=InterfacePoETypeChoices + choices=InterfacePoETypeChoices, + distinct=False, ) rf_role = django_filters.MultipleChoiceFilter( - choices=WirelessRoleChoices + choices=WirelessRoleChoices, + distinct=False, ) class Meta: @@ -903,6 +949,7 @@ class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, + distinct=False, null_value=None ) rear_port_id = django_filters.ModelMultipleChoiceFilter( @@ -921,6 +968,7 @@ class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, + distinct=False, null_value=None ) front_port_id = django_filters.ModelMultipleChoiceFilter( @@ -955,25 +1003,30 @@ class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponent class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemTemplate.objects.all(), + distinct=False, label=_('Parent inventory item (ID)'), ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemRole.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=InventoryItemRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) @@ -999,15 +1052,18 @@ class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeCompo class DeviceRoleFilterSet(NestedGroupModelFilterSet): config_template_id = django_filters.ModelMultipleChoiceFilter( queryset=ConfigTemplate.objects.all(), + distinct=False, label=_('Config template (ID)'), ) parent_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceRole.objects.all(), + distinct=False, label=_('Parent device role (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=DeviceRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent device role (slug)'), ) @@ -1034,11 +1090,13 @@ class DeviceRoleFilterSet(NestedGroupModelFilterSet): class PlatformFilterSet(NestedGroupModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Platform.objects.all(), + distinct=False, label=_('Immediate parent platform (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=Platform.objects.all(), + distinct=False, to_field_name='slug', label=_('Immediate parent platform (slug)'), ) @@ -1058,11 +1116,13 @@ class PlatformFilterSet(NestedGroupModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer', queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) @@ -1072,6 +1132,7 @@ class PlatformFilterSet(NestedGroupModelFilterSet): ) config_template_id = django_filters.ModelMultipleChoiceFilter( queryset=ConfigTemplate.objects.all(), + distinct=False, label=_('Config template (ID)'), ) @@ -1099,22 +1160,26 @@ class DeviceFilterSet( manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='device_type__manufacturer', queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='device_type__manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) device_type = django_filters.ModelMultipleChoiceFilter( field_name='device_type__slug', queryset=DeviceType.objects.all(), + distinct=False, to_field_name='slug', label=_('Device type (slug)'), ) device_type_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), + distinct=False, label=_('Device type (ID)'), ) role_id = TreeNodeMultipleChoiceFilter( @@ -1176,11 +1241,13 @@ class DeviceFilterSet( ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) @@ -1200,6 +1267,7 @@ class DeviceFilterSet( rack_id = django_filters.ModelMultipleChoiceFilter( field_name='rack', queryset=Rack.objects.all(), + distinct=False, label=_('Rack (ID)'), ) parent_bay_id = django_filters.ModelMultipleChoiceFilter( @@ -1209,22 +1277,26 @@ class DeviceFilterSet( ) cluster_id = django_filters.ModelMultipleChoiceFilter( queryset=Cluster.objects.all(), + distinct=False, label=_('VM cluster (ID)'), ) cluster_group = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group__slug', queryset=ClusterGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Cluster group (slug)'), ) cluster_group_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group', queryset=ClusterGroup.objects.all(), + distinct=False, label=_('Cluster group (ID)'), ) model = django_filters.ModelMultipleChoiceFilter( field_name='device_type__slug', queryset=DeviceType.objects.all(), + distinct=False, to_field_name='slug', label=_('Device model (slug)'), ) @@ -1233,6 +1305,7 @@ class DeviceFilterSet( ) status = django_filters.MultipleChoiceFilter( choices=DeviceStatusChoices, + distinct=False, null_value=None ) is_full_depth = django_filters.BooleanFilter( @@ -1257,6 +1330,7 @@ class DeviceFilterSet( virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_chassis', queryset=VirtualChassis.objects.all(), + distinct=False, label=_('Virtual chassis (ID)'), ) virtual_chassis_member = django_filters.BooleanFilter( @@ -1265,6 +1339,7 @@ class DeviceFilterSet( ) config_template_id = django_filters.ModelMultipleChoiceFilter( queryset=ConfigTemplate.objects.all(), + distinct=False, label=_('Config template (ID)'), ) console_ports = django_filters.BooleanFilter( @@ -1302,6 +1377,7 @@ class DeviceFilterSet( oob_ip_id = django_filters.ModelMultipleChoiceFilter( field_name='oob_ip', queryset=IPAddress.objects.all(), + distinct=False, label=_('OOB IP (ID)'), ) has_virtual_device_context = django_filters.BooleanFilter( @@ -1404,11 +1480,13 @@ class VirtualDeviceContextFilterSet(PrimaryModelFilterSet, TenancyFilterSet, Pri device_id = django_filters.ModelMultipleChoiceFilter( field_name='device', queryset=Device.objects.all(), + distinct=False, label=_('VDC (ID)') ) device = django_filters.ModelMultipleChoiceFilter( field_name='device', queryset=Device.objects.all(), + distinct=False, label=_('Device model') ) interface_id = django_filters.ModelMultipleChoiceFilter( @@ -1417,7 +1495,8 @@ class VirtualDeviceContextFilterSet(PrimaryModelFilterSet, TenancyFilterSet, Pri label=_('Interface (ID)') ) status = django_filters.MultipleChoiceFilter( - choices=VirtualDeviceContextStatusChoices + choices=VirtualDeviceContextStatusChoices, + distinct=False, ) has_primary_ip = django_filters.BooleanFilter( method='_has_primary_ip', @@ -1454,22 +1533,26 @@ class ModuleFilterSet(PrimaryModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='module_type__manufacturer', queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='module_type__manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) module_type_id = django_filters.ModelMultipleChoiceFilter( field_name='module_type', queryset=ModuleType.objects.all(), + distinct=False, label=_('Module type (ID)'), ) module_type = django_filters.ModelMultipleChoiceFilter( field_name='module_type__model', queryset=ModuleType.objects.all(), + distinct=False, to_field_name='model', label=_('Module type (model)'), ) @@ -1508,48 +1591,57 @@ class ModuleFilterSet(PrimaryModelFilterSet): site_id = django_filters.ModelMultipleChoiceFilter( field_name='device__site', queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='device__site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) location_id = django_filters.ModelMultipleChoiceFilter( field_name='device__location', queryset=Location.objects.all(), + distinct=False, label=_('Location (ID)'), ) location = django_filters.ModelMultipleChoiceFilter( field_name='device__location__slug', queryset=Location.objects.all(), + distinct=False, to_field_name='slug', label=_('Location (slug)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='device__rack', queryset=Rack.objects.all(), + distinct=False, label=_('Rack (ID)'), ) rack = django_filters.ModelMultipleChoiceFilter( field_name='device__rack__name', queryset=Rack.objects.all(), + distinct=False, to_field_name='name', label=_('Rack (name)'), ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), + distinct=False, label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), + distinct=False, to_field_name='name', label=_('Device (name)'), ) status = django_filters.MultipleChoiceFilter( choices=ModuleStatusChoices, + distinct=False, null_value=None ) serial = MultiValueCharFilter( @@ -1606,91 +1698,108 @@ class DeviceComponentFilterSet(OwnerFilterMixin, NetBoxModelFilterSet): site_id = django_filters.ModelMultipleChoiceFilter( field_name='_site', queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='_site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) location_id = django_filters.ModelMultipleChoiceFilter( field_name='_location', queryset=Location.objects.all(), + distinct=False, label=_('Location (ID)'), ) location = django_filters.ModelMultipleChoiceFilter( field_name='_location__slug', queryset=Location.objects.all(), + distinct=False, to_field_name='slug', label=_('Location (slug)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='_rack', queryset=Rack.objects.all(), + distinct=False, label=_('Rack (ID)'), ) rack = django_filters.ModelMultipleChoiceFilter( field_name='_rack__name', queryset=Rack.objects.all(), + distinct=False, to_field_name='name', label=_('Rack (name)'), ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), + distinct=False, label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), + distinct=False, to_field_name='name', label=_('Device (name)'), ) device_type_id = django_filters.ModelMultipleChoiceFilter( field_name='device__device_type', queryset=DeviceType.objects.all(), + distinct=False, label=_('Device type (ID)'), ) device_type = django_filters.ModelMultipleChoiceFilter( field_name='device__device_type__model', queryset=DeviceType.objects.all(), + distinct=False, to_field_name='model', label=_('Device type (model)'), ) device_role_id = django_filters.ModelMultipleChoiceFilter( field_name='device__role', queryset=DeviceRole.objects.all(), + distinct=False, label=_('Device role (ID)'), ) device_role = django_filters.ModelMultipleChoiceFilter( field_name='device__role__slug', queryset=DeviceRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Device role (slug)'), ) virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis', queryset=VirtualChassis.objects.all(), + distinct=False, label=_('Virtual Chassis (ID)') ) virtual_chassis = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis__name', queryset=VirtualChassis.objects.all(), + distinct=False, to_field_name='name', label=_('Virtual Chassis'), ) device_status = django_filters.MultipleChoiceFilter( choices=DeviceStatusChoices, + distinct=False, field_name='device__status', ) tenant_id = django_filters.ModelMultipleChoiceFilter( field_name='device__tenant', queryset=Tenant.objects.all(), + distinct=False, label=_('Tenant (ID)'), ) tenant = django_filters.ModelMultipleChoiceFilter( field_name='device__tenant__slug', queryset=Tenant.objects.all(), + distinct=False, to_field_name='slug', label=_('Tenant (slug)'), ) @@ -1712,6 +1821,7 @@ class ModularDeviceComponentFilterSet(DeviceComponentFilterSet): """ module_id = django_filters.ModelMultipleChoiceFilter( queryset=Module.objects.all(), + distinct=False, label=_('Module (ID)'), ) @@ -1719,6 +1829,7 @@ class ModularDeviceComponentFilterSet(DeviceComponentFilterSet): class CabledObjectFilterSet(django_filters.FilterSet): cable_id = django_filters.ModelMultipleChoiceFilter( queryset=Cable.objects.all(), + distinct=False, label=_('Cable (ID)'), ) cabled = django_filters.BooleanFilter( @@ -1753,6 +1864,7 @@ class PathEndpointFilterSet(django_filters.FilterSet): class ConsolePortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=ConsolePortTypeChoices, + distinct=False, null_value=None ) @@ -1767,6 +1879,7 @@ class ConsolePortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSe class ConsoleServerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=ConsolePortTypeChoices, + distinct=False, null_value=None ) @@ -1781,6 +1894,7 @@ class ConsoleServerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFi class PowerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=PowerPortTypeChoices, + distinct=False, null_value=None ) @@ -1796,18 +1910,22 @@ class PowerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, class PowerOutletFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=PowerOutletTypeChoices, + distinct=False, null_value=None ) feed_leg = django_filters.MultipleChoiceFilter( choices=PowerOutletFeedLegChoices, + distinct=False, null_value=None ) power_port_id = django_filters.ModelMultipleChoiceFilter( queryset=PowerPort.objects.all(), + distinct=False, label=_('Power port (ID)'), ) status = django_filters.MultipleChoiceFilter( choices=PowerOutletStatusChoices, + distinct=False, null_value=None ) @@ -1936,6 +2054,7 @@ class MACAddressFilterSet(PrimaryModelFilterSet): class CommonInterfaceFilterSet(django_filters.FilterSet): mode = django_filters.MultipleChoiceFilter( choices=InterfaceModeChoices, + distinct=False, label=_('802.1Q Mode') ) vlan_id = django_filters.CharFilter( @@ -1949,11 +2068,13 @@ class CommonInterfaceFilterSet(django_filters.FilterSet): vrf_id = django_filters.ModelMultipleChoiceFilter( field_name='vrf', queryset=VRF.objects.all(), + distinct=False, label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), + distinct=False, to_field_name='rd', label=_('VRF (RD)'), ) @@ -1971,11 +2092,13 @@ class CommonInterfaceFilterSet(django_filters.FilterSet): vlan_translation_policy_id = django_filters.ModelMultipleChoiceFilter( field_name='vlan_translation_policy', queryset=VLANTranslationPolicy.objects.all(), + distinct=False, label=_('VLAN Translation Policy (ID)'), ) vlan_translation_policy = django_filters.ModelMultipleChoiceFilter( field_name='vlan_translation_policy__name', queryset=VLANTranslationPolicy.objects.all(), + distinct=False, to_field_name='name', label=_('VLAN Translation Policy'), ) @@ -2035,21 +2158,25 @@ class InterfaceFilterSet( parent_id = django_filters.ModelMultipleChoiceFilter( field_name='parent', queryset=Interface.objects.all(), + distinct=False, label=_('Parent interface (ID)'), ) bridge_id = django_filters.ModelMultipleChoiceFilter( field_name='bridge', queryset=Interface.objects.all(), + distinct=False, label=_('Bridged interface (ID)'), ) lag_id = django_filters.ModelMultipleChoiceFilter( field_name='lag', queryset=Interface.objects.all(), + distinct=False, label=_('LAG interface (ID)'), ) speed = MultiValueNumberFilter() duplex = django_filters.MultipleChoiceFilter( - choices=InterfaceDuplexChoices + choices=InterfaceDuplexChoices, + distinct=False, ) mac_address = MultiValueMACAddressFilter( field_name='mac_addresses__mac_address', @@ -2058,30 +2185,37 @@ class InterfaceFilterSet( primary_mac_address_id = django_filters.ModelMultipleChoiceFilter( field_name='primary_mac_address', queryset=MACAddress.objects.all(), + distinct=False, label=_('Primary MAC address (ID)'), ) primary_mac_address = django_filters.ModelMultipleChoiceFilter( field_name='primary_mac_address__mac_address', queryset=MACAddress.objects.all(), + distinct=False, to_field_name='mac_address', label=_('Primary MAC address'), ) wwn = MultiValueWWNFilter() poe_mode = django_filters.MultipleChoiceFilter( - choices=InterfacePoEModeChoices + choices=InterfacePoEModeChoices, + distinct=False, ) poe_type = django_filters.MultipleChoiceFilter( - choices=InterfacePoETypeChoices + choices=InterfacePoETypeChoices, + distinct=False, ) type = django_filters.MultipleChoiceFilter( choices=InterfaceTypeChoices, + distinct=False, null_value=None ) rf_role = django_filters.MultipleChoiceFilter( - choices=WirelessRoleChoices + choices=WirelessRoleChoices, + distinct=False, ) rf_channel = django_filters.MultipleChoiceFilter( - choices=WirelessChannelChoices + choices=WirelessChannelChoices, + distinct=False, ) vdc_id = django_filters.ModelMultipleChoiceFilter( field_name='vdcs', @@ -2107,6 +2241,7 @@ class InterfaceFilterSet( ) wireless_link_id = django_filters.ModelMultipleChoiceFilter( queryset=WirelessLink.objects.all(), + distinct=False, label=_('Wireless link') ) virtual_circuit_id = django_filters.ModelMultipleChoiceFilter( @@ -2168,6 +2303,7 @@ class InterfaceFilterSet( class FrontPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, + distinct=False, null_value=None ) rear_port_id = django_filters.ModelMultipleChoiceFilter( @@ -2189,6 +2325,7 @@ class FrontPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet) class RearPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, + distinct=False, null_value=None ) front_port_id = django_filters.ModelMultipleChoiceFilter( @@ -2210,6 +2347,7 @@ class RearPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet): class ModuleBayFilterSet(ModularDeviceComponentFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=ModuleBay.objects.all(), + distinct=False, label=_('Parent module bay (ID)'), ) installed_module_id = django_filters.ModelMultipleChoiceFilter( @@ -2227,11 +2365,13 @@ class ModuleBayFilterSet(ModularDeviceComponentFilterSet): class DeviceBayFilterSet(DeviceComponentFilterSet): installed_device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), + distinct=False, label=_('Installed device (ID)'), ) installed_device = django_filters.ModelMultipleChoiceFilter( field_name='installed_device__name', queryset=Device.objects.all(), + distinct=False, to_field_name='name', label=_('Installed device (name)'), ) @@ -2245,25 +2385,30 @@ class DeviceBayFilterSet(DeviceComponentFilterSet): class InventoryItemFilterSet(DeviceComponentFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItem.objects.all(), + distinct=False, label=_('Parent inventory item (ID)'), ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), + distinct=False, label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), + distinct=False, to_field_name='slug', label=_('Manufacturer (slug)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemRole.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=InventoryItemRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) @@ -2274,6 +2419,7 @@ class InventoryItemFilterSet(DeviceComponentFilterSet): ) status = django_filters.MultipleChoiceFilter( choices=InventoryItemStatusChoices, + distinct=False, null_value=None ) @@ -2306,11 +2452,13 @@ class InventoryItemRoleFilterSet(OrganizationalModelFilterSet): class VirtualChassisFilterSet(PrimaryModelFilterSet): master_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), + distinct=False, label=_('Master (ID)'), ) master = django_filters.ModelMultipleChoiceFilter( field_name='master__name', queryset=Device.objects.all(), + distinct=False, to_field_name='name', label=_('Master (name)'), ) @@ -2343,22 +2491,26 @@ class VirtualChassisFilterSet(PrimaryModelFilterSet): site_id = django_filters.ModelMultipleChoiceFilter( field_name='master__site', queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='master__site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) tenant_id = django_filters.ModelMultipleChoiceFilter( field_name='master__tenant', queryset=Tenant.objects.all(), + distinct=False, label=_('Tenant (ID)'), ) tenant = django_filters.ModelMultipleChoiceFilter( field_name='master__tenant__slug', queryset=Tenant.objects.all(), + distinct=False, to_field_name='slug', label=_('Tenant (slug)'), ) @@ -2400,16 +2552,20 @@ class CableFilterSet(TenancyFilterSet, PrimaryModelFilterSet): label=_('Unterminated'), ) type = django_filters.MultipleChoiceFilter( - choices=CableTypeChoices + choices=CableTypeChoices, + distinct=False, ) status = django_filters.MultipleChoiceFilter( - choices=LinkStatusChoices + choices=LinkStatusChoices, + distinct=False, ) profile = django_filters.MultipleChoiceFilter( - choices=CableProfileChoices + choices=CableProfileChoices, + distinct=False, ) color = django_filters.MultipleChoiceFilter( - choices=ColorChoices + choices=ColorChoices, + distinct=False, ) device_id = MultiValueNumberFilter( method='filter_by_termination' @@ -2591,11 +2747,13 @@ class PowerPanelFilterSet(PrimaryModelFilterSet, ContactModelFilterSet): ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) @@ -2651,25 +2809,30 @@ class PowerFeedFilterSet(PrimaryModelFilterSet, CabledObjectFilterSet, PathEndpo site_id = django_filters.ModelMultipleChoiceFilter( field_name='power_panel__site', queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='power_panel__site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site name (slug)'), ) power_panel_id = django_filters.ModelMultipleChoiceFilter( queryset=PowerPanel.objects.all(), + distinct=False, label=_('Power panel (ID)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='rack', queryset=Rack.objects.all(), + distinct=False, label=_('Rack (ID)'), ) status = django_filters.MultipleChoiceFilter( choices=PowerFeedStatusChoices, + distinct=False, null_value=None ) diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index a5f23feec..36860cdac 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -49,6 +49,7 @@ class ScriptFilterSet(BaseFilterSet): ) module_id = django_filters.ModelMultipleChoiceFilter( queryset=ScriptModule.objects.all(), + distinct=False, label=_('Script module (ID)'), ) @@ -71,7 +72,8 @@ class WebhookFilterSet(OwnerFilterMixin, NetBoxModelFilterSet): label=_('Search'), ) http_method = django_filters.MultipleChoiceFilter( - choices=WebhookHttpMethodChoices + choices=WebhookHttpMethodChoices, + distinct=False, ) payload_url = MultiValueCharFilter( lookup_expr='icontains' @@ -111,7 +113,8 @@ class EventRuleFilterSet(OwnerFilterMixin, NetBoxModelFilterSet): method='filter_event_type' ) action_type = django_filters.MultipleChoiceFilter( - choices=EventRuleActionChoices + choices=EventRuleActionChoices, + distinct=False, ) action_object_type = MultiValueContentTypeFilter() action_object_id = MultiValueNumberFilter() @@ -142,7 +145,8 @@ class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): label=_('Search'), ) type = django_filters.MultipleChoiceFilter( - choices=CustomFieldTypeChoices + choices=CustomFieldTypeChoices, + distinct=False, ) object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ObjectType.objects.all(), @@ -153,15 +157,18 @@ class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) related_object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ObjectType.objects.all(), + distinct=False, field_name='related_object_type' ) related_object_type = MultiValueContentTypeFilter() choice_set_id = django_filters.ModelMultipleChoiceFilter( - queryset=CustomFieldChoiceSet.objects.all() + queryset=CustomFieldChoiceSet.objects.all(), + distinct=False, ) choice_set = django_filters.ModelMultipleChoiceFilter( field_name='choice_set__name', queryset=CustomFieldChoiceSet.objects.all(), + distinct=False, to_field_name='name' ) @@ -260,10 +267,12 @@ class ExportTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) data_source_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data source (ID)'), ) data_file_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data file (ID)'), ) @@ -299,11 +308,13 @@ class SavedFilterFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) @@ -345,6 +356,7 @@ class TableConfigFilterSet(ChangeLoggedModelFilterSet): ) object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ObjectType.objects.all(), + distinct=False, field_name='object_type' ) object_type = MultiValueContentTypeFilter( @@ -352,11 +364,13 @@ class TableConfigFilterSet(ChangeLoggedModelFilterSet): ) user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) @@ -398,11 +412,13 @@ class BookmarkFilterSet(BaseFilterSet): object_type = MultiValueContentTypeFilter() user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) @@ -483,20 +499,24 @@ class JournalEntryFilterSet(NetBoxModelFilterSet): created = django_filters.DateTimeFromToRangeFilter() assigned_object_type = MultiValueContentTypeFilter() assigned_object_type_id = django_filters.ModelMultipleChoiceFilter( - queryset=ContentType.objects.all() + queryset=ContentType.objects.all(), + distinct=False, ) created_by_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), + distinct=False, label=_('User (ID)'), ) created_by = django_filters.ModelMultipleChoiceFilter( field_name='created_by__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) kind = django_filters.MultipleChoiceFilter( - choices=JournalEntryKindChoices + choices=JournalEntryKindChoices, + distinct=False, ) class Meta: @@ -581,14 +601,17 @@ class TaggedItemFilterSet(BaseFilterSet): ) object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ContentType.objects.all(), + distinct=False, field_name='content_type_id' ) tag_id = django_filters.ModelMultipleChoiceFilter( - queryset=Tag.objects.all() + queryset=Tag.objects.all(), + distinct=False, ) tag = django_filters.ModelMultipleChoiceFilter( field_name='tag__slug', queryset=Tag.objects.all(), + distinct=False, to_field_name='slug', ) @@ -614,10 +637,12 @@ class ConfigContextProfileFilterSet(PrimaryModelFilterSet): ) data_source_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data source (ID)'), ) data_file_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data file (ID)'), ) @@ -645,11 +670,13 @@ class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) profile_id = django_filters.ModelMultipleChoiceFilter( queryset=ConfigContextProfile.objects.all(), + distinct=False, label=_('Profile (ID)'), ) profile = django_filters.ModelMultipleChoiceFilter( field_name='profile__name', queryset=ConfigContextProfile.objects.all(), + distinct=False, to_field_name='name', label=_('Profile (name)'), ) @@ -786,10 +813,12 @@ class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) data_source_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data source (ID)'), ) data_file_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data file (ID)'), ) @@ -815,10 +844,12 @@ class ConfigTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet): ) data_source_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data source (ID)'), ) data_file_id = django_filters.ModelMultipleChoiceFilter( queryset=DataSource.objects.all(), + distinct=False, label=_('Data file (ID)'), ) tag = TagFilter() diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index d2168a6ce..319271de6 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -167,11 +167,13 @@ class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi ) rir_id = django_filters.ModelMultipleChoiceFilter( queryset=RIR.objects.all(), + distinct=False, label=_('RIR (ID)'), ) rir = django_filters.ModelMultipleChoiceFilter( field_name='rir__slug', queryset=RIR.objects.all(), + distinct=False, to_field_name='slug', label=_('RIR (slug)'), ) @@ -207,11 +209,13 @@ class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): rir_id = django_filters.ModelMultipleChoiceFilter( queryset=RIR.objects.all(), + distinct=False, label=_('RIR (ID)'), ) rir = django_filters.ModelMultipleChoiceFilter( field_name='rir__slug', queryset=RIR.objects.all(), + distinct=False, to_field_name='slug', label=_('RIR (slug)'), ) @@ -233,11 +237,13 @@ class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): class ASNFilterSet(PrimaryModelFilterSet, TenancyFilterSet): rir_id = django_filters.ModelMultipleChoiceFilter( queryset=RIR.objects.all(), + distinct=False, label=_('RIR (ID)'), ) rir = django_filters.ModelMultipleChoiceFilter( field_name='rir__slug', queryset=RIR.objects.all(), + distinct=False, to_field_name='slug', label=_('RIR (slug)'), ) @@ -343,11 +349,13 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet, ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), + distinct=False, label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), + distinct=False, to_field_name='rd', label=_('VRF (RD)'), ) @@ -365,17 +373,20 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet, vlan_group_id = django_filters.ModelMultipleChoiceFilter( field_name='vlan__group', queryset=VLANGroup.objects.all(), + distinct=False, to_field_name='id', label=_('VLAN Group (ID)'), ) vlan_group = django_filters.ModelMultipleChoiceFilter( field_name='vlan__group__slug', queryset=VLANGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('VLAN Group (slug)'), ) vlan_id = django_filters.ModelMultipleChoiceFilter( queryset=VLAN.objects.all(), + distinct=False, label=_('VLAN (ID)'), ) vlan_vid = django_filters.NumberFilter( @@ -384,16 +395,19 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet, ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=PrefixStatusChoices, + distinct=False, null_value=None ) @@ -487,26 +501,31 @@ class IPRangeFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), + distinct=False, label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), + distinct=False, to_field_name='rd', label=_('VRF (RD)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=IPRangeStatusChoices, + distinct=False, null_value=None ) parent = MultiValueCharFilter( @@ -589,11 +608,13 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), + distinct=False, label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), + distinct=False, to_field_name='rd', label=_('VRF (RD)'), ) @@ -666,10 +687,12 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi ) status = django_filters.MultipleChoiceFilter( choices=IPAddressStatusChoices, + distinct=False, null_value=None ) role = django_filters.MultipleChoiceFilter( - choices=IPAddressRoleChoices + choices=IPAddressRoleChoices, + distinct=False, ) service_id = django_filters.ModelMultipleChoiceFilter( field_name='services', @@ -679,6 +702,7 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi nat_inside_id = django_filters.ModelMultipleChoiceFilter( field_name='nat_inside', queryset=IPAddress.objects.all(), + distinct=False, label=_('NAT inside IP address (ID)'), ) @@ -800,10 +824,12 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi @register_filterset class FHRPGroupFilterSet(PrimaryModelFilterSet): protocol = django_filters.MultipleChoiceFilter( - choices=FHRPGroupProtocolChoices + choices=FHRPGroupProtocolChoices, + distinct=False, ) auth_type = django_filters.MultipleChoiceFilter( - choices=FHRPGroupAuthTypeChoices + choices=FHRPGroupAuthTypeChoices, + distinct=False, ) related_ip = django_filters.ModelMultipleChoiceFilter( queryset=IPAddress.objects.all(), @@ -850,6 +876,7 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet): interface_type = MultiValueContentTypeFilter() group_id = django_filters.ModelMultipleChoiceFilter( queryset=FHRPGroup.objects.all(), + distinct=False, label=_('Group (ID)'), ) device = MultiValueCharFilter( @@ -980,36 +1007,43 @@ class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet): ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=VLANGroup.objects.all(), + distinct=False, label=_('Group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=VLANGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Group'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), + distinct=False, label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), + distinct=False, to_field_name='slug', label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=VLANStatusChoices, + distinct=False, null_value=None ) available_at_site = django_filters.ModelChoiceFilter( @@ -1025,10 +1059,12 @@ class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet): method='get_for_virtualmachine' ) qinq_role = django_filters.MultipleChoiceFilter( - choices=VLANQinQRoleChoices + choices=VLANQinQRoleChoices, + distinct=False, ) qinq_svlan_id = django_filters.ModelMultipleChoiceFilter( queryset=VLAN.objects.all(), + distinct=False, label=_('Q-in-Q SVLAN (ID)'), ) qinq_svlan_vid = MultiValueNumberFilter( @@ -1123,11 +1159,13 @@ class VLANTranslationPolicyFilterSet(PrimaryModelFilterSet): class VLANTranslationRuleFilterSet(NetBoxModelFilterSet): policy_id = django_filters.ModelMultipleChoiceFilter( queryset=VLANTranslationPolicy.objects.all(), + distinct=False, label=_('VLAN Translation Policy (ID)'), ) policy = django_filters.ModelMultipleChoiceFilter( field_name='policy__name', queryset=VLANTranslationPolicy.objects.all(), + distinct=False, to_field_name='name', label=_('VLAN Translation Policy (name)'), ) @@ -1266,22 +1304,26 @@ class PrimaryIPFilterSet(django_filters.FilterSet): primary_ip4_id = django_filters.ModelMultipleChoiceFilter( field_name='primary_ip4', queryset=IPAddress.objects.all(), + distinct=False, label=_('Primary IPv4 (ID)'), ) primary_ip4 = django_filters.ModelMultipleChoiceFilter( field_name='primary_ip4__address', queryset=IPAddress.objects.all(), + distinct=False, to_field_name='address', label=_('Primary IPv4 (address)'), ) primary_ip6_id = django_filters.ModelMultipleChoiceFilter( field_name='primary_ip6', queryset=IPAddress.objects.all(), + distinct=False, label=_('Primary IPv6 (ID)'), ) primary_ip6 = django_filters.ModelMultipleChoiceFilter( field_name='primary_ip6__address', queryset=IPAddress.objects.all(), + distinct=False, to_field_name='address', label=_('Primary IPv6 (address)'), ) diff --git a/netbox/tenancy/filtersets.py b/netbox/tenancy/filtersets.py index 4db66691d..ec70e6858 100644 --- a/netbox/tenancy/filtersets.py +++ b/netbox/tenancy/filtersets.py @@ -29,11 +29,13 @@ __all__ = ( class ContactGroupFilterSet(NestedGroupModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=ContactGroup.objects.all(), + distinct=False, label=_('Parent contact group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=ContactGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent contact group (slug)'), ) @@ -113,6 +115,7 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet): object_type = MultiValueContentTypeFilter() contact_id = django_filters.ModelMultipleChoiceFilter( queryset=Contact.objects.all(), + distinct=False, label=_('Contact (ID)'), ) group_id = TreeNodeMultipleChoiceFilter( @@ -130,11 +133,13 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet): ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=ContactRole.objects.all(), + distinct=False, label=_('Contact role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=ContactRole.objects.all(), + distinct=False, to_field_name='slug', label=_('Contact role (slug)'), ) @@ -179,11 +184,13 @@ class ContactModelFilterSet(django_filters.FilterSet): class TenantGroupFilterSet(NestedGroupModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=TenantGroup.objects.all(), + distinct=False, label=_('Parent tenant group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=TenantGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent tenant group (slug)'), ) @@ -256,10 +263,12 @@ class TenancyFilterSet(django_filters.FilterSet): ) tenant_id = django_filters.ModelMultipleChoiceFilter( queryset=Tenant.objects.all(), + distinct=False, label=_('Tenant (ID)'), ) tenant = django_filters.ModelMultipleChoiceFilter( queryset=Tenant.objects.all(), + distinct=False, field_name='tenant__slug', to_field_name='slug', label=_('Tenant (slug)'), diff --git a/netbox/users/filterset_mixins.py b/netbox/users/filterset_mixins.py index 8969d1d70..113d6211c 100644 --- a/netbox/users/filterset_mixins.py +++ b/netbox/users/filterset_mixins.py @@ -14,22 +14,26 @@ class OwnerFilterMixin(django_filters.FilterSet): """ owner_group_id = django_filters.ModelMultipleChoiceFilter( queryset=OwnerGroup.objects.all(), + distinct=False, field_name='owner__group', label=_('Owner Group (ID)'), ) owner_group = django_filters.ModelMultipleChoiceFilter( queryset=OwnerGroup.objects.all(), + distinct=False, field_name='owner__group__name', to_field_name='name', label=_('Owner Group (name)'), ) owner_id = django_filters.ModelMultipleChoiceFilter( queryset=Owner.objects.all(), + distinct=False, label=_('Owner (ID)'), ) owner = django_filters.ModelMultipleChoiceFilter( field_name='owner__name', queryset=Owner.objects.all(), + distinct=False, to_field_name='name', label=_('Owner (name)'), ) diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 56727cabb..0d2e599d8 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -131,11 +131,13 @@ class TokenFilterSet(BaseFilterSet): user_id = django_filters.ModelMultipleChoiceFilter( field_name='user', queryset=User.objects.all(), + distinct=False, label=_('User'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), + distinct=False, to_field_name='username', label=_('User (name)'), ) @@ -280,11 +282,13 @@ class OwnerFilterSet(BaseFilterSet): ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=OwnerGroup.objects.all(), + distinct=False, label=_('Group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__name', queryset=OwnerGroup.objects.all(), + distinct=False, to_field_name='name', label=_('Group (name)'), ) diff --git a/netbox/virtualization/filtersets.py b/netbox/virtualization/filtersets.py index 1c4821dec..6b3bdb424 100644 --- a/netbox/virtualization/filtersets.py +++ b/netbox/virtualization/filtersets.py @@ -49,26 +49,31 @@ class ClusterGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet) class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ScopedFilterSet, ContactModelFilterSet): group_id = django_filters.ModelMultipleChoiceFilter( queryset=ClusterGroup.objects.all(), + distinct=False, label=_('Parent group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=ClusterGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Parent group (slug)'), ) type_id = django_filters.ModelMultipleChoiceFilter( queryset=ClusterType.objects.all(), + distinct=False, label=_('Cluster type (ID)'), ) type = django_filters.ModelMultipleChoiceFilter( field_name='type__slug', queryset=ClusterType.objects.all(), + distinct=False, to_field_name='slug', label=_('Cluster type (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=ClusterStatusChoices, + distinct=False, null_value=None ) @@ -96,51 +101,61 @@ class VirtualMachineFilterSet( ): status = django_filters.MultipleChoiceFilter( choices=VirtualMachineStatusChoices, + distinct=False, null_value=None ) start_on_boot = django_filters.MultipleChoiceFilter( choices=VirtualMachineStartOnBootChoices, + distinct=False, null_value=None ) cluster_group_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group', queryset=ClusterGroup.objects.all(), + distinct=False, label=_('Cluster group (ID)'), ) cluster_group = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group__slug', queryset=ClusterGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Cluster group (slug)'), ) cluster_type_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__type', queryset=ClusterType.objects.all(), + distinct=False, label=_('Cluster type (ID)'), ) cluster_type = django_filters.ModelMultipleChoiceFilter( field_name='cluster__type__slug', queryset=ClusterType.objects.all(), + distinct=False, to_field_name='slug', label=_('Cluster type (slug)'), ) cluster_id = django_filters.ModelMultipleChoiceFilter( queryset=Cluster.objects.all(), + distinct=False, label=_('Cluster (ID)'), ) cluster = django_filters.ModelMultipleChoiceFilter( field_name='cluster__name', queryset=Cluster.objects.all(), + distinct=False, to_field_name='name', label=_('Cluster'), ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), + distinct=False, label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), + distinct=False, to_field_name='name', label=_('Device'), ) @@ -172,11 +187,13 @@ class VirtualMachineFilterSet( ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), + distinct=False, label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), + distinct=False, to_field_name='slug', label=_('Site (slug)'), ) @@ -218,6 +235,7 @@ class VirtualMachineFilterSet( ) config_template_id = django_filters.ModelMultipleChoiceFilter( queryset=ConfigTemplate.objects.all(), + distinct=False, label=_('Config template (ID)'), ) @@ -260,33 +278,39 @@ class VMInterfaceFilterSet(CommonInterfaceFilterSet, OwnerFilterMixin, NetBoxMod cluster_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__cluster', queryset=Cluster.objects.all(), + distinct=False, label=_('Cluster (ID)'), ) cluster = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__cluster__name', queryset=Cluster.objects.all(), + distinct=False, to_field_name='name', label=_('Cluster'), ) virtual_machine_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine', queryset=VirtualMachine.objects.all(), + distinct=False, label=_('Virtual machine (ID)'), ) virtual_machine = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__name', queryset=VirtualMachine.objects.all(), + distinct=False, to_field_name='name', label=_('Virtual machine'), ) parent_id = django_filters.ModelMultipleChoiceFilter( field_name='parent', queryset=VMInterface.objects.all(), + distinct=False, label=_('Parent interface (ID)'), ) bridge_id = django_filters.ModelMultipleChoiceFilter( field_name='bridge', queryset=VMInterface.objects.all(), + distinct=False, label=_('Bridged interface (ID)'), ) mac_address = MultiValueMACAddressFilter( @@ -296,11 +320,13 @@ class VMInterfaceFilterSet(CommonInterfaceFilterSet, OwnerFilterMixin, NetBoxMod primary_mac_address_id = django_filters.ModelMultipleChoiceFilter( field_name='primary_mac_address', queryset=MACAddress.objects.all(), + distinct=False, label=_('Primary MAC address (ID)'), ) primary_mac_address = django_filters.ModelMultipleChoiceFilter( field_name='primary_mac_address__mac_address', queryset=MACAddress.objects.all(), + distinct=False, to_field_name='mac_address', label=_('Primary MAC address'), ) @@ -323,11 +349,13 @@ class VirtualDiskFilterSet(OwnerFilterMixin, NetBoxModelFilterSet): virtual_machine_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine', queryset=VirtualMachine.objects.all(), + distinct=False, label=_('Virtual machine (ID)'), ) virtual_machine = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__name', queryset=VirtualMachine.objects.all(), + distinct=False, to_field_name='name', label=_('Virtual machine'), ) diff --git a/netbox/vpn/filtersets.py b/netbox/vpn/filtersets.py index e7bd95be1..b819de106 100644 --- a/netbox/vpn/filtersets.py +++ b/netbox/vpn/filtersets.py @@ -38,28 +38,34 @@ class TunnelGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): @register_filterset class TunnelFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet): status = django_filters.MultipleChoiceFilter( - choices=TunnelStatusChoices + choices=TunnelStatusChoices, + distinct=False, ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=TunnelGroup.objects.all(), + distinct=False, label=_('Tunnel group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=TunnelGroup.objects.all(), + distinct=False, to_field_name='slug', label=_('Tunnel group (slug)'), ) encapsulation = django_filters.MultipleChoiceFilter( - choices=TunnelEncapsulationChoices + choices=TunnelEncapsulationChoices, + distinct=False, ) ipsec_profile_id = django_filters.ModelMultipleChoiceFilter( queryset=IPSecProfile.objects.all(), + distinct=False, label=_('IPSec profile (ID)'), ) ipsec_profile = django_filters.ModelMultipleChoiceFilter( field_name='ipsec_profile__name', queryset=IPSecProfile.objects.all(), + distinct=False, to_field_name='name', label=_('IPSec profile (name)'), ) @@ -83,16 +89,19 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet): tunnel_id = django_filters.ModelMultipleChoiceFilter( field_name='tunnel', queryset=Tunnel.objects.all(), + distinct=False, label=_('Tunnel (ID)'), ) tunnel = django_filters.ModelMultipleChoiceFilter( field_name='tunnel__name', queryset=Tunnel.objects.all(), + distinct=False, to_field_name='name', label=_('Tunnel (name)'), ) role = django_filters.MultipleChoiceFilter( - choices=TunnelTerminationRoleChoices + choices=TunnelTerminationRoleChoices, + distinct=False, ) termination_type = MultiValueContentTypeFilter() interface = django_filters.ModelMultipleChoiceFilter( @@ -120,6 +129,7 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet): outside_ip_id = django_filters.ModelMultipleChoiceFilter( field_name='outside_ip', queryset=IPAddress.objects.all(), + distinct=False, label=_('Outside IP (ID)'), ) @@ -142,16 +152,20 @@ class IKEProposalFilterSet(PrimaryModelFilterSet): label=_('IKE policy (name)'), ) authentication_method = django_filters.MultipleChoiceFilter( - choices=AuthenticationMethodChoices + choices=AuthenticationMethodChoices, + distinct=False, ) encryption_algorithm = django_filters.MultipleChoiceFilter( - choices=EncryptionAlgorithmChoices + choices=EncryptionAlgorithmChoices, + distinct=False, ) authentication_algorithm = django_filters.MultipleChoiceFilter( - choices=AuthenticationAlgorithmChoices + choices=AuthenticationAlgorithmChoices, + distinct=False, ) group = django_filters.MultipleChoiceFilter( - choices=DHGroupChoices + choices=DHGroupChoices, + distinct=False, ) class Meta: @@ -171,10 +185,12 @@ class IKEProposalFilterSet(PrimaryModelFilterSet): @register_filterset class IKEPolicyFilterSet(PrimaryModelFilterSet): version = django_filters.MultipleChoiceFilter( - choices=IKEVersionChoices + choices=IKEVersionChoices, + distinct=False, ) mode = django_filters.MultipleChoiceFilter( - choices=IKEModeChoices + choices=IKEModeChoices, + distinct=False, ) ike_proposal_id = django_filters.ModelMultipleChoiceFilter( field_name='proposals', @@ -214,10 +230,12 @@ class IPSecProposalFilterSet(PrimaryModelFilterSet): label=_('IPSec policy (name)'), ) encryption_algorithm = django_filters.MultipleChoiceFilter( - choices=EncryptionAlgorithmChoices + choices=EncryptionAlgorithmChoices, + distinct=False, ) authentication_algorithm = django_filters.MultipleChoiceFilter( - choices=AuthenticationAlgorithmChoices + choices=AuthenticationAlgorithmChoices, + distinct=False, ) class Meta: @@ -237,7 +255,8 @@ class IPSecProposalFilterSet(PrimaryModelFilterSet): @register_filterset class IPSecPolicyFilterSet(PrimaryModelFilterSet): pfs_group = django_filters.MultipleChoiceFilter( - choices=DHGroupChoices + choices=DHGroupChoices, + distinct=False, ) ipsec_proposal_id = django_filters.ModelMultipleChoiceFilter( field_name='proposals', @@ -266,25 +285,30 @@ class IPSecPolicyFilterSet(PrimaryModelFilterSet): @register_filterset class IPSecProfileFilterSet(PrimaryModelFilterSet): mode = django_filters.MultipleChoiceFilter( - choices=IPSecModeChoices + choices=IPSecModeChoices, + distinct=False, ) ike_policy_id = django_filters.ModelMultipleChoiceFilter( queryset=IKEPolicy.objects.all(), + distinct=False, label=_('IKE policy (ID)'), ) ike_policy = django_filters.ModelMultipleChoiceFilter( field_name='ike_policy__name', queryset=IKEPolicy.objects.all(), + distinct=False, to_field_name='name', label=_('IKE policy (name)'), ) ipsec_policy_id = django_filters.ModelMultipleChoiceFilter( queryset=IPSecPolicy.objects.all(), + distinct=False, label=_('IPSec policy (ID)'), ) ipsec_policy = django_filters.ModelMultipleChoiceFilter( field_name='ipsec_policy__name', queryset=IPSecPolicy.objects.all(), + distinct=False, to_field_name='name', label=_('IPSec policy (name)'), ) @@ -307,10 +331,12 @@ class IPSecProfileFilterSet(PrimaryModelFilterSet): class L2VPNFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet): type = django_filters.MultipleChoiceFilter( choices=L2VPNTypeChoices, + distinct=False, null_value=None ) status = django_filters.MultipleChoiceFilter( choices=L2VPNStatusChoices, + distinct=False, ) import_target_id = django_filters.ModelMultipleChoiceFilter( field_name='import_targets', @@ -354,11 +380,13 @@ class L2VPNFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilter class L2VPNTerminationFilterSet(NetBoxModelFilterSet): l2vpn_id = django_filters.ModelMultipleChoiceFilter( queryset=L2VPN.objects.all(), + distinct=False, label=_('L2VPN (ID)'), ) l2vpn = django_filters.ModelMultipleChoiceFilter( field_name='l2vpn__slug', queryset=L2VPN.objects.all(), + distinct=False, to_field_name='slug', label=_('L2VPN (slug)'), ) @@ -443,6 +471,7 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet): ) assigned_object_type_id = django_filters.ModelMultipleChoiceFilter( queryset=ObjectType.objects.all(), + distinct=False, field_name='assigned_object_type' ) assigned_object_type = MultiValueContentTypeFilter() diff --git a/netbox/wireless/filtersets.py b/netbox/wireless/filtersets.py index 3d10497ea..2790a29f6 100644 --- a/netbox/wireless/filtersets.py +++ b/netbox/wireless/filtersets.py @@ -22,11 +22,13 @@ __all__ = ( @register_filterset class WirelessLANGroupFilterSet(NestedGroupModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( - queryset=WirelessLANGroup.objects.all() + queryset=WirelessLANGroup.objects.all(), + distinct=False, ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=WirelessLANGroup.objects.all(), + distinct=False, to_field_name='slug' ) ancestor_id = TreeNodeMultipleChoiceFilter( @@ -60,20 +62,24 @@ class WirelessLANFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilter to_field_name='slug' ) status = django_filters.MultipleChoiceFilter( - choices=WirelessLANStatusChoices + choices=WirelessLANStatusChoices, + distinct=False, ) vlan_id = django_filters.ModelMultipleChoiceFilter( - queryset=VLAN.objects.all() + queryset=VLAN.objects.all(), + distinct=False, ) interface_id = django_filters.ModelMultipleChoiceFilter( queryset=Interface.objects.all(), field_name='interfaces' ) auth_type = django_filters.MultipleChoiceFilter( - choices=WirelessAuthTypeChoices + choices=WirelessAuthTypeChoices, + distinct=False, ) auth_cipher = django_filters.MultipleChoiceFilter( - choices=WirelessAuthCipherChoices + choices=WirelessAuthCipherChoices, + distinct=False, ) class Meta: @@ -93,19 +99,24 @@ class WirelessLANFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilter @register_filterset class WirelessLinkFilterSet(PrimaryModelFilterSet, TenancyFilterSet): interface_a_id = django_filters.ModelMultipleChoiceFilter( - queryset=Interface.objects.all() + queryset=Interface.objects.all(), + distinct=False, ) interface_b_id = django_filters.ModelMultipleChoiceFilter( - queryset=Interface.objects.all() + queryset=Interface.objects.all(), + distinct=False, ) status = django_filters.MultipleChoiceFilter( - choices=LinkStatusChoices + choices=LinkStatusChoices, + distinct=False, ) auth_type = django_filters.MultipleChoiceFilter( - choices=WirelessAuthTypeChoices + choices=WirelessAuthTypeChoices, + distinct=False, ) auth_cipher = django_filters.MultipleChoiceFilter( - choices=WirelessAuthCipherChoices + choices=WirelessAuthCipherChoices, + distinct=False, ) class Meta: