Sfoglia il codice sorgente

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
Jeremy Stretch 1 giorno fa
parent
commit
1190adde2b

+ 37 - 0
netbox/circuits/filtersets.py

@@ -99,11 +99,13 @@ class ProviderFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
 class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
 class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='provider__slug',
         field_name='provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
@@ -127,11 +129,13 @@ class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
 class ProviderNetworkFilterSet(PrimaryModelFilterSet):
 class ProviderNetworkFilterSet(PrimaryModelFilterSet):
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='provider__slug',
         field_name='provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
@@ -163,22 +167,26 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
 class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
 class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='provider__slug',
         field_name='provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_account',
         field_name='provider_account',
         queryset=ProviderAccount.objects.all(),
         queryset=ProviderAccount.objects.all(),
+        distinct=False,
         label=_('Provider account (ID)'),
         label=_('Provider account (ID)'),
     )
     )
     provider_account = django_filters.ModelMultipleChoiceFilter(
     provider_account = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_account__account',
         field_name='provider_account__account',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='account',
         to_field_name='account',
         label=_('Provider account (account)'),
         label=_('Provider account (account)'),
     )
     )
@@ -189,16 +197,19 @@ class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt
     )
     )
     type_id = django_filters.ModelMultipleChoiceFilter(
     type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=CircuitType.objects.all(),
         queryset=CircuitType.objects.all(),
+        distinct=False,
         label=_('Circuit type (ID)'),
         label=_('Circuit type (ID)'),
     )
     )
     type = django_filters.ModelMultipleChoiceFilter(
     type = django_filters.ModelMultipleChoiceFilter(
         field_name='type__slug',
         field_name='type__slug',
         queryset=CircuitType.objects.all(),
         queryset=CircuitType.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Circuit type (slug)'),
         label=_('Circuit type (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=CircuitStatusChoices,
         choices=CircuitStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     region_id = TreeNodeMultipleChoiceFilter(
     region_id = TreeNodeMultipleChoiceFilter(
@@ -245,10 +256,12 @@ class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt
     )
     )
     termination_a_id = django_filters.ModelMultipleChoiceFilter(
     termination_a_id = django_filters.ModelMultipleChoiceFilter(
         queryset=CircuitTermination.objects.all(),
         queryset=CircuitTermination.objects.all(),
+        distinct=False,
         label=_('Termination A (ID)'),
         label=_('Termination A (ID)'),
     )
     )
     termination_z_id = django_filters.ModelMultipleChoiceFilter(
     termination_z_id = django_filters.ModelMultipleChoiceFilter(
         queryset=CircuitTermination.objects.all(),
         queryset=CircuitTermination.objects.all(),
+        distinct=False,
         label=_('Termination A (ID)'),
         label=_('Termination A (ID)'),
     )
     )
 
 
@@ -279,6 +292,7 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
     )
     )
     circuit_id = django_filters.ModelMultipleChoiceFilter(
     circuit_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Circuit.objects.all(),
         queryset=Circuit.objects.all(),
+        distinct=False,
         label=_('Circuit'),
         label=_('Circuit'),
     )
     )
     termination_type = MultiValueContentTypeFilter()
     termination_type = MultiValueContentTypeFilter()
@@ -310,12 +324,14 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
     )
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         field_name='_site',
         field_name='_site',
         label=_('Site (ID)'),
         label=_('Site (ID)'),
     )
     )
     site = django_filters.ModelMultipleChoiceFilter(
     site = django_filters.ModelMultipleChoiceFilter(
         field_name='_site__slug',
         field_name='_site__slug',
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Site (slug)'),
         label=_('Site (slug)'),
     )
     )
@@ -334,17 +350,20 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
     )
     )
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ProviderNetwork.objects.all(),
         queryset=ProviderNetwork.objects.all(),
+        distinct=False,
         field_name='_provider_network',
         field_name='_provider_network',
         label=_('ProviderNetwork (ID)'),
         label=_('ProviderNetwork (ID)'),
     )
     )
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         field_name='circuit__provider_id',
         field_name='circuit__provider_id',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='circuit__provider__slug',
         field_name='circuit__provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
@@ -414,11 +433,13 @@ class CircuitGroupAssignmentFilterSet(NetBoxModelFilterSet):
     )
     )
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=CircuitGroup.objects.all(),
         queryset=CircuitGroup.objects.all(),
+        distinct=False,
         label=_('Circuit group (ID)'),
         label=_('Circuit group (ID)'),
     )
     )
     group = django_filters.ModelMultipleChoiceFilter(
     group = django_filters.ModelMultipleChoiceFilter(
         field_name='group__slug',
         field_name='group__slug',
         queryset=CircuitGroup.objects.all(),
         queryset=CircuitGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Circuit group (slug)'),
         label=_('Circuit group (slug)'),
     )
     )
@@ -488,41 +509,49 @@ class VirtualCircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_network__provider',
         field_name='provider_network__provider',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_network__provider__slug',
         field_name='provider_network__provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_account',
         field_name='provider_account',
         queryset=ProviderAccount.objects.all(),
         queryset=ProviderAccount.objects.all(),
+        distinct=False,
         label=_('Provider account (ID)'),
         label=_('Provider account (ID)'),
     )
     )
     provider_account = django_filters.ModelMultipleChoiceFilter(
     provider_account = django_filters.ModelMultipleChoiceFilter(
         field_name='provider_account__account',
         field_name='provider_account__account',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='account',
         to_field_name='account',
         label=_('Provider account (account)'),
         label=_('Provider account (account)'),
     )
     )
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ProviderNetwork.objects.all(),
         queryset=ProviderNetwork.objects.all(),
+        distinct=False,
         label=_('Provider network (ID)'),
         label=_('Provider network (ID)'),
     )
     )
     type_id = django_filters.ModelMultipleChoiceFilter(
     type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VirtualCircuitType.objects.all(),
         queryset=VirtualCircuitType.objects.all(),
+        distinct=False,
         label=_('Virtual circuit type (ID)'),
         label=_('Virtual circuit type (ID)'),
     )
     )
     type = django_filters.ModelMultipleChoiceFilter(
     type = django_filters.ModelMultipleChoiceFilter(
         field_name='type__slug',
         field_name='type__slug',
         queryset=VirtualCircuitType.objects.all(),
         queryset=VirtualCircuitType.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Virtual circuit type (slug)'),
         label=_('Virtual circuit type (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=CircuitStatusChoices,
         choices=CircuitStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
 
 
@@ -548,41 +577,49 @@ class VirtualCircuitTerminationFilterSet(NetBoxModelFilterSet):
     )
     )
     virtual_circuit_id = django_filters.ModelMultipleChoiceFilter(
     virtual_circuit_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VirtualCircuit.objects.all(),
         queryset=VirtualCircuit.objects.all(),
+        distinct=False,
         label=_('Virtual circuit'),
         label=_('Virtual circuit'),
     )
     )
     role = django_filters.MultipleChoiceFilter(
     role = django_filters.MultipleChoiceFilter(
         choices=VirtualCircuitTerminationRoleChoices,
         choices=VirtualCircuitTerminationRoleChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     provider_id = django_filters.ModelMultipleChoiceFilter(
     provider_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_circuit__provider_network__provider',
         field_name='virtual_circuit__provider_network__provider',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         label=_('Provider (ID)'),
         label=_('Provider (ID)'),
     )
     )
     provider = django_filters.ModelMultipleChoiceFilter(
     provider = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_circuit__provider_network__provider__slug',
         field_name='virtual_circuit__provider_network__provider__slug',
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Provider (slug)'),
         label=_('Provider (slug)'),
     )
     )
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
     provider_account_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_circuit__provider_account',
         field_name='virtual_circuit__provider_account',
         queryset=ProviderAccount.objects.all(),
         queryset=ProviderAccount.objects.all(),
+        distinct=False,
         label=_('Provider account (ID)'),
         label=_('Provider account (ID)'),
     )
     )
     provider_account = django_filters.ModelMultipleChoiceFilter(
     provider_account = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_circuit__provider_account__account',
         field_name='virtual_circuit__provider_account__account',
         queryset=ProviderAccount.objects.all(),
         queryset=ProviderAccount.objects.all(),
+        distinct=False,
         to_field_name='account',
         to_field_name='account',
         label=_('Provider account (account)'),
         label=_('Provider account (account)'),
     )
     )
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
     provider_network_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ProviderNetwork.objects.all(),
         queryset=ProviderNetwork.objects.all(),
+        distinct=False,
         field_name='virtual_circuit__provider_network',
         field_name='virtual_circuit__provider_network',
         label=_('Provider network (ID)'),
         label=_('Provider network (ID)'),
     )
     )
     interface_id = django_filters.ModelMultipleChoiceFilter(
     interface_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Interface.objects.all(),
         queryset=Interface.objects.all(),
+        distinct=False,
         field_name='interface',
         field_name='interface',
         label=_('Interface (ID)'),
         label=_('Interface (ID)'),
     )
     )

+ 11 - 1
netbox/core/filtersets.py

@@ -25,14 +25,17 @@ __all__ = (
 class DataSourceFilterSet(PrimaryModelFilterSet):
 class DataSourceFilterSet(PrimaryModelFilterSet):
     type = django_filters.MultipleChoiceFilter(
     type = django_filters.MultipleChoiceFilter(
         choices=get_data_backend_choices,
         choices=get_data_backend_choices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=DataSourceStatusChoices,
         choices=DataSourceStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     sync_interval = django_filters.MultipleChoiceFilter(
     sync_interval = django_filters.MultipleChoiceFilter(
         choices=JobIntervalChoices,
         choices=JobIntervalChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
 
 
@@ -57,11 +60,13 @@ class DataFileFilterSet(ChangeLoggedModelFilterSet):
     )
     )
     source_id = django_filters.ModelMultipleChoiceFilter(
     source_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data source (ID)'),
         label=_('Data source (ID)'),
     )
     )
     source = django_filters.ModelMultipleChoiceFilter(
     source = django_filters.ModelMultipleChoiceFilter(
         field_name='source__name',
         field_name='source__name',
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Data source (name)'),
         label=_('Data source (name)'),
     )
     )
@@ -86,6 +91,7 @@ class JobFilterSet(BaseFilterSet):
     )
     )
     object_type_id = django_filters.ModelMultipleChoiceFilter(
     object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ObjectType.objects.with_feature('jobs'),
         queryset=ObjectType.objects.with_feature('jobs'),
+        distinct=False,
         field_name='object_type_id',
         field_name='object_type_id',
     )
     )
     object_type = MultiValueContentTypeFilter()
     object_type = MultiValueContentTypeFilter()
@@ -127,6 +133,7 @@ class JobFilterSet(BaseFilterSet):
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=JobStatusChoices,
         choices=JobStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     queue_name = django_filters.CharFilter()
     queue_name = django_filters.CharFilter()
@@ -182,16 +189,19 @@ class ObjectChangeFilterSet(BaseFilterSet):
     time = django_filters.DateTimeFromToRangeFilter()
     time = django_filters.DateTimeFromToRangeFilter()
     changed_object_type = MultiValueContentTypeFilter()
     changed_object_type = MultiValueContentTypeFilter()
     changed_object_type_id = django_filters.ModelMultipleChoiceFilter(
     changed_object_type_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=ContentType.objects.all()
+        queryset=ContentType.objects.all(),
+        distinct=False,
     )
     )
     related_object_type = MultiValueContentTypeFilter()
     related_object_type = MultiValueContentTypeFilter()
     user_id = django_filters.ModelMultipleChoiceFilter(
     user_id = django_filters.ModelMultipleChoiceFilter(
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User (ID)'),
         label=_('User (ID)'),
     )
     )
     user = django_filters.ModelMultipleChoiceFilter(
     user = django_filters.ModelMultipleChoiceFilter(
         field_name='user__username',
         field_name='user__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User name'),
         label=_('User name'),
     )
     )

+ 2 - 0
netbox/dcim/base_filtersets.py

@@ -43,12 +43,14 @@ class ScopedFilterSet(BaseFilterSet):
     )
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         field_name='_site',
         field_name='_site',
         label=_('Site (ID)'),
         label=_('Site (ID)'),
     )
     )
     site = django_filters.ModelMultipleChoiceFilter(
     site = django_filters.ModelMultipleChoiceFilter(
         field_name='_site__slug',
         field_name='_site__slug',
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Site (slug)'),
         label=_('Site (slug)'),
     )
     )

File diff suppressed because it is too large
+ 166 - 14
netbox/dcim/filtersets.py


+ 38 - 7
netbox/extras/filtersets.py

@@ -49,6 +49,7 @@ class ScriptFilterSet(BaseFilterSet):
     )
     )
     module_id = django_filters.ModelMultipleChoiceFilter(
     module_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ScriptModule.objects.all(),
         queryset=ScriptModule.objects.all(),
+        distinct=False,
         label=_('Script module (ID)'),
         label=_('Script module (ID)'),
     )
     )
 
 
@@ -71,7 +72,8 @@ class WebhookFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
         label=_('Search'),
         label=_('Search'),
     )
     )
     http_method = django_filters.MultipleChoiceFilter(
     http_method = django_filters.MultipleChoiceFilter(
-        choices=WebhookHttpMethodChoices
+        choices=WebhookHttpMethodChoices,
+        distinct=False,
     )
     )
     payload_url = MultiValueCharFilter(
     payload_url = MultiValueCharFilter(
         lookup_expr='icontains'
         lookup_expr='icontains'
@@ -111,7 +113,8 @@ class EventRuleFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
         method='filter_event_type'
         method='filter_event_type'
     )
     )
     action_type = django_filters.MultipleChoiceFilter(
     action_type = django_filters.MultipleChoiceFilter(
-        choices=EventRuleActionChoices
+        choices=EventRuleActionChoices,
+        distinct=False,
     )
     )
     action_object_type = MultiValueContentTypeFilter()
     action_object_type = MultiValueContentTypeFilter()
     action_object_id = MultiValueNumberFilter()
     action_object_id = MultiValueNumberFilter()
@@ -142,7 +145,8 @@ class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
         label=_('Search'),
         label=_('Search'),
     )
     )
     type = django_filters.MultipleChoiceFilter(
     type = django_filters.MultipleChoiceFilter(
-        choices=CustomFieldTypeChoices
+        choices=CustomFieldTypeChoices,
+        distinct=False,
     )
     )
     object_type_id = django_filters.ModelMultipleChoiceFilter(
     object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
@@ -153,15 +157,18 @@ class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     related_object_type_id = django_filters.ModelMultipleChoiceFilter(
     related_object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
+        distinct=False,
         field_name='related_object_type'
         field_name='related_object_type'
     )
     )
     related_object_type = MultiValueContentTypeFilter()
     related_object_type = MultiValueContentTypeFilter()
     choice_set_id = django_filters.ModelMultipleChoiceFilter(
     choice_set_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=CustomFieldChoiceSet.objects.all()
+        queryset=CustomFieldChoiceSet.objects.all(),
+        distinct=False,
     )
     )
     choice_set = django_filters.ModelMultipleChoiceFilter(
     choice_set = django_filters.ModelMultipleChoiceFilter(
         field_name='choice_set__name',
         field_name='choice_set__name',
         queryset=CustomFieldChoiceSet.objects.all(),
         queryset=CustomFieldChoiceSet.objects.all(),
+        distinct=False,
         to_field_name='name'
         to_field_name='name'
     )
     )
 
 
@@ -260,10 +267,12 @@ class ExportTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     data_source_id = django_filters.ModelMultipleChoiceFilter(
     data_source_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data source (ID)'),
         label=_('Data source (ID)'),
     )
     )
     data_file_id = django_filters.ModelMultipleChoiceFilter(
     data_file_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data file (ID)'),
         label=_('Data file (ID)'),
     )
     )
 
 
@@ -299,11 +308,13 @@ class SavedFilterFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     user_id = django_filters.ModelMultipleChoiceFilter(
     user_id = django_filters.ModelMultipleChoiceFilter(
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User (ID)'),
         label=_('User (ID)'),
     )
     )
     user = django_filters.ModelMultipleChoiceFilter(
     user = django_filters.ModelMultipleChoiceFilter(
         field_name='user__username',
         field_name='user__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User (name)'),
         label=_('User (name)'),
     )
     )
@@ -345,6 +356,7 @@ class TableConfigFilterSet(ChangeLoggedModelFilterSet):
     )
     )
     object_type_id = django_filters.ModelMultipleChoiceFilter(
     object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
+        distinct=False,
         field_name='object_type'
         field_name='object_type'
     )
     )
     object_type = MultiValueContentTypeFilter(
     object_type = MultiValueContentTypeFilter(
@@ -352,11 +364,13 @@ class TableConfigFilterSet(ChangeLoggedModelFilterSet):
     )
     )
     user_id = django_filters.ModelMultipleChoiceFilter(
     user_id = django_filters.ModelMultipleChoiceFilter(
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User (ID)'),
         label=_('User (ID)'),
     )
     )
     user = django_filters.ModelMultipleChoiceFilter(
     user = django_filters.ModelMultipleChoiceFilter(
         field_name='user__username',
         field_name='user__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User (name)'),
         label=_('User (name)'),
     )
     )
@@ -398,11 +412,13 @@ class BookmarkFilterSet(BaseFilterSet):
     object_type = MultiValueContentTypeFilter()
     object_type = MultiValueContentTypeFilter()
     user_id = django_filters.ModelMultipleChoiceFilter(
     user_id = django_filters.ModelMultipleChoiceFilter(
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User (ID)'),
         label=_('User (ID)'),
     )
     )
     user = django_filters.ModelMultipleChoiceFilter(
     user = django_filters.ModelMultipleChoiceFilter(
         field_name='user__username',
         field_name='user__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User (name)'),
         label=_('User (name)'),
     )
     )
@@ -483,20 +499,24 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
     created = django_filters.DateTimeFromToRangeFilter()
     created = django_filters.DateTimeFromToRangeFilter()
     assigned_object_type = MultiValueContentTypeFilter()
     assigned_object_type = MultiValueContentTypeFilter()
     assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
     assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=ContentType.objects.all()
+        queryset=ContentType.objects.all(),
+        distinct=False,
     )
     )
     created_by_id = django_filters.ModelMultipleChoiceFilter(
     created_by_id = django_filters.ModelMultipleChoiceFilter(
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User (ID)'),
         label=_('User (ID)'),
     )
     )
     created_by = django_filters.ModelMultipleChoiceFilter(
     created_by = django_filters.ModelMultipleChoiceFilter(
         field_name='created_by__username',
         field_name='created_by__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User (name)'),
         label=_('User (name)'),
     )
     )
     kind = django_filters.MultipleChoiceFilter(
     kind = django_filters.MultipleChoiceFilter(
-        choices=JournalEntryKindChoices
+        choices=JournalEntryKindChoices,
+        distinct=False,
     )
     )
 
 
     class Meta:
     class Meta:
@@ -581,14 +601,17 @@ class TaggedItemFilterSet(BaseFilterSet):
     )
     )
     object_type_id = django_filters.ModelMultipleChoiceFilter(
     object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ContentType.objects.all(),
         queryset=ContentType.objects.all(),
+        distinct=False,
         field_name='content_type_id'
         field_name='content_type_id'
     )
     )
     tag_id = django_filters.ModelMultipleChoiceFilter(
     tag_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=Tag.objects.all()
+        queryset=Tag.objects.all(),
+        distinct=False,
     )
     )
     tag = django_filters.ModelMultipleChoiceFilter(
     tag = django_filters.ModelMultipleChoiceFilter(
         field_name='tag__slug',
         field_name='tag__slug',
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
     )
     )
 
 
@@ -614,10 +637,12 @@ class ConfigContextProfileFilterSet(PrimaryModelFilterSet):
     )
     )
     data_source_id = django_filters.ModelMultipleChoiceFilter(
     data_source_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data source (ID)'),
         label=_('Data source (ID)'),
     )
     )
     data_file_id = django_filters.ModelMultipleChoiceFilter(
     data_file_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data file (ID)'),
         label=_('Data file (ID)'),
     )
     )
 
 
@@ -645,11 +670,13 @@ class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     profile_id = django_filters.ModelMultipleChoiceFilter(
     profile_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ConfigContextProfile.objects.all(),
         queryset=ConfigContextProfile.objects.all(),
+        distinct=False,
         label=_('Profile (ID)'),
         label=_('Profile (ID)'),
     )
     )
     profile = django_filters.ModelMultipleChoiceFilter(
     profile = django_filters.ModelMultipleChoiceFilter(
         field_name='profile__name',
         field_name='profile__name',
         queryset=ConfigContextProfile.objects.all(),
         queryset=ConfigContextProfile.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Profile (name)'),
         label=_('Profile (name)'),
     )
     )
@@ -786,10 +813,12 @@ class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     data_source_id = django_filters.ModelMultipleChoiceFilter(
     data_source_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data source (ID)'),
         label=_('Data source (ID)'),
     )
     )
     data_file_id = django_filters.ModelMultipleChoiceFilter(
     data_file_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data file (ID)'),
         label=_('Data file (ID)'),
     )
     )
 
 
@@ -815,10 +844,12 @@ class ConfigTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
     )
     )
     data_source_id = django_filters.ModelMultipleChoiceFilter(
     data_source_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data source (ID)'),
         label=_('Data source (ID)'),
     )
     )
     data_file_id = django_filters.ModelMultipleChoiceFilter(
     data_file_id = django_filters.ModelMultipleChoiceFilter(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
+        distinct=False,
         label=_('Data file (ID)'),
         label=_('Data file (ID)'),
     )
     )
     tag = TagFilter()
     tag = TagFilter()

+ 46 - 4
netbox/ipam/filtersets.py

@@ -167,11 +167,13 @@ class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
     )
     )
     rir_id = django_filters.ModelMultipleChoiceFilter(
     rir_id = django_filters.ModelMultipleChoiceFilter(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         label=_('RIR (ID)'),
         label=_('RIR (ID)'),
     )
     )
     rir = django_filters.ModelMultipleChoiceFilter(
     rir = django_filters.ModelMultipleChoiceFilter(
         field_name='rir__slug',
         field_name='rir__slug',
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('RIR (slug)'),
         label=_('RIR (slug)'),
     )
     )
@@ -207,11 +209,13 @@ class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
 class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
 class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
     rir_id = django_filters.ModelMultipleChoiceFilter(
     rir_id = django_filters.ModelMultipleChoiceFilter(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         label=_('RIR (ID)'),
         label=_('RIR (ID)'),
     )
     )
     rir = django_filters.ModelMultipleChoiceFilter(
     rir = django_filters.ModelMultipleChoiceFilter(
         field_name='rir__slug',
         field_name='rir__slug',
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('RIR (slug)'),
         label=_('RIR (slug)'),
     )
     )
@@ -233,11 +237,13 @@ class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
 class ASNFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
 class ASNFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
     rir_id = django_filters.ModelMultipleChoiceFilter(
     rir_id = django_filters.ModelMultipleChoiceFilter(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         label=_('RIR (ID)'),
         label=_('RIR (ID)'),
     )
     )
     rir = django_filters.ModelMultipleChoiceFilter(
     rir = django_filters.ModelMultipleChoiceFilter(
         field_name='rir__slug',
         field_name='rir__slug',
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('RIR (slug)'),
         label=_('RIR (slug)'),
     )
     )
@@ -343,11 +349,13 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet,
     )
     )
     vrf_id = django_filters.ModelMultipleChoiceFilter(
     vrf_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         label=_('VRF'),
         label=_('VRF'),
     )
     )
     vrf = django_filters.ModelMultipleChoiceFilter(
     vrf = django_filters.ModelMultipleChoiceFilter(
         field_name='vrf__rd',
         field_name='vrf__rd',
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         to_field_name='rd',
         to_field_name='rd',
         label=_('VRF (RD)'),
         label=_('VRF (RD)'),
     )
     )
@@ -365,17 +373,20 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet,
     vlan_group_id = django_filters.ModelMultipleChoiceFilter(
     vlan_group_id = django_filters.ModelMultipleChoiceFilter(
         field_name='vlan__group',
         field_name='vlan__group',
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
+        distinct=False,
         to_field_name='id',
         to_field_name='id',
         label=_('VLAN Group (ID)'),
         label=_('VLAN Group (ID)'),
     )
     )
     vlan_group = django_filters.ModelMultipleChoiceFilter(
     vlan_group = django_filters.ModelMultipleChoiceFilter(
         field_name='vlan__group__slug',
         field_name='vlan__group__slug',
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('VLAN Group (slug)'),
         label=_('VLAN Group (slug)'),
     )
     )
     vlan_id = django_filters.ModelMultipleChoiceFilter(
     vlan_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VLAN.objects.all(),
         queryset=VLAN.objects.all(),
+        distinct=False,
         label=_('VLAN (ID)'),
         label=_('VLAN (ID)'),
     )
     )
     vlan_vid = django_filters.NumberFilter(
     vlan_vid = django_filters.NumberFilter(
@@ -384,16 +395,19 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet,
     )
     )
     role_id = django_filters.ModelMultipleChoiceFilter(
     role_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         label=_('Role (ID)'),
         label=_('Role (ID)'),
     )
     )
     role = django_filters.ModelMultipleChoiceFilter(
     role = django_filters.ModelMultipleChoiceFilter(
         field_name='role__slug',
         field_name='role__slug',
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Role (slug)'),
         label=_('Role (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=PrefixStatusChoices,
         choices=PrefixStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
 
 
@@ -487,26 +501,31 @@ class IPRangeFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilt
     )
     )
     vrf_id = django_filters.ModelMultipleChoiceFilter(
     vrf_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         label=_('VRF'),
         label=_('VRF'),
     )
     )
     vrf = django_filters.ModelMultipleChoiceFilter(
     vrf = django_filters.ModelMultipleChoiceFilter(
         field_name='vrf__rd',
         field_name='vrf__rd',
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         to_field_name='rd',
         to_field_name='rd',
         label=_('VRF (RD)'),
         label=_('VRF (RD)'),
     )
     )
     role_id = django_filters.ModelMultipleChoiceFilter(
     role_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         label=_('Role (ID)'),
         label=_('Role (ID)'),
     )
     )
     role = django_filters.ModelMultipleChoiceFilter(
     role = django_filters.ModelMultipleChoiceFilter(
         field_name='role__slug',
         field_name='role__slug',
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Role (slug)'),
         label=_('Role (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=IPRangeStatusChoices,
         choices=IPRangeStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     parent = MultiValueCharFilter(
     parent = MultiValueCharFilter(
@@ -589,11 +608,13 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
     )
     )
     vrf_id = django_filters.ModelMultipleChoiceFilter(
     vrf_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         label=_('VRF'),
         label=_('VRF'),
     )
     )
     vrf = django_filters.ModelMultipleChoiceFilter(
     vrf = django_filters.ModelMultipleChoiceFilter(
         field_name='vrf__rd',
         field_name='vrf__rd',
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
+        distinct=False,
         to_field_name='rd',
         to_field_name='rd',
         label=_('VRF (RD)'),
         label=_('VRF (RD)'),
     )
     )
@@ -666,10 +687,12 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=IPAddressStatusChoices,
         choices=IPAddressStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     role = django_filters.MultipleChoiceFilter(
     role = django_filters.MultipleChoiceFilter(
-        choices=IPAddressRoleChoices
+        choices=IPAddressRoleChoices,
+        distinct=False,
     )
     )
     service_id = django_filters.ModelMultipleChoiceFilter(
     service_id = django_filters.ModelMultipleChoiceFilter(
         field_name='services',
         field_name='services',
@@ -679,6 +702,7 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
     nat_inside_id = django_filters.ModelMultipleChoiceFilter(
     nat_inside_id = django_filters.ModelMultipleChoiceFilter(
         field_name='nat_inside',
         field_name='nat_inside',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         label=_('NAT inside IP address (ID)'),
         label=_('NAT inside IP address (ID)'),
     )
     )
 
 
@@ -800,10 +824,12 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi
 @register_filterset
 @register_filterset
 class FHRPGroupFilterSet(PrimaryModelFilterSet):
 class FHRPGroupFilterSet(PrimaryModelFilterSet):
     protocol = django_filters.MultipleChoiceFilter(
     protocol = django_filters.MultipleChoiceFilter(
-        choices=FHRPGroupProtocolChoices
+        choices=FHRPGroupProtocolChoices,
+        distinct=False,
     )
     )
     auth_type = django_filters.MultipleChoiceFilter(
     auth_type = django_filters.MultipleChoiceFilter(
-        choices=FHRPGroupAuthTypeChoices
+        choices=FHRPGroupAuthTypeChoices,
+        distinct=False,
     )
     )
     related_ip = django_filters.ModelMultipleChoiceFilter(
     related_ip = django_filters.ModelMultipleChoiceFilter(
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
@@ -850,6 +876,7 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet):
     interface_type = MultiValueContentTypeFilter()
     interface_type = MultiValueContentTypeFilter()
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=FHRPGroup.objects.all(),
         queryset=FHRPGroup.objects.all(),
+        distinct=False,
         label=_('Group (ID)'),
         label=_('Group (ID)'),
     )
     )
     device = MultiValueCharFilter(
     device = MultiValueCharFilter(
@@ -980,36 +1007,43 @@ class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
     )
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         label=_('Site (ID)'),
         label=_('Site (ID)'),
     )
     )
     site = django_filters.ModelMultipleChoiceFilter(
     site = django_filters.ModelMultipleChoiceFilter(
         field_name='site__slug',
         field_name='site__slug',
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Site (slug)'),
         label=_('Site (slug)'),
     )
     )
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
+        distinct=False,
         label=_('Group (ID)'),
         label=_('Group (ID)'),
     )
     )
     group = django_filters.ModelMultipleChoiceFilter(
     group = django_filters.ModelMultipleChoiceFilter(
         field_name='group__slug',
         field_name='group__slug',
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Group'),
         label=_('Group'),
     )
     )
     role_id = django_filters.ModelMultipleChoiceFilter(
     role_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         label=_('Role (ID)'),
         label=_('Role (ID)'),
     )
     )
     role = django_filters.ModelMultipleChoiceFilter(
     role = django_filters.ModelMultipleChoiceFilter(
         field_name='role__slug',
         field_name='role__slug',
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Role (slug)'),
         label=_('Role (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=VLANStatusChoices,
         choices=VLANStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     available_at_site = django_filters.ModelChoiceFilter(
     available_at_site = django_filters.ModelChoiceFilter(
@@ -1025,10 +1059,12 @@ class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
         method='get_for_virtualmachine'
         method='get_for_virtualmachine'
     )
     )
     qinq_role = django_filters.MultipleChoiceFilter(
     qinq_role = django_filters.MultipleChoiceFilter(
-        choices=VLANQinQRoleChoices
+        choices=VLANQinQRoleChoices,
+        distinct=False,
     )
     )
     qinq_svlan_id = django_filters.ModelMultipleChoiceFilter(
     qinq_svlan_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VLAN.objects.all(),
         queryset=VLAN.objects.all(),
+        distinct=False,
         label=_('Q-in-Q SVLAN (ID)'),
         label=_('Q-in-Q SVLAN (ID)'),
     )
     )
     qinq_svlan_vid = MultiValueNumberFilter(
     qinq_svlan_vid = MultiValueNumberFilter(
@@ -1123,11 +1159,13 @@ class VLANTranslationPolicyFilterSet(PrimaryModelFilterSet):
 class VLANTranslationRuleFilterSet(NetBoxModelFilterSet):
 class VLANTranslationRuleFilterSet(NetBoxModelFilterSet):
     policy_id = django_filters.ModelMultipleChoiceFilter(
     policy_id = django_filters.ModelMultipleChoiceFilter(
         queryset=VLANTranslationPolicy.objects.all(),
         queryset=VLANTranslationPolicy.objects.all(),
+        distinct=False,
         label=_('VLAN Translation Policy (ID)'),
         label=_('VLAN Translation Policy (ID)'),
     )
     )
     policy = django_filters.ModelMultipleChoiceFilter(
     policy = django_filters.ModelMultipleChoiceFilter(
         field_name='policy__name',
         field_name='policy__name',
         queryset=VLANTranslationPolicy.objects.all(),
         queryset=VLANTranslationPolicy.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('VLAN Translation Policy (name)'),
         label=_('VLAN Translation Policy (name)'),
     )
     )
@@ -1266,22 +1304,26 @@ class PrimaryIPFilterSet(django_filters.FilterSet):
     primary_ip4_id = django_filters.ModelMultipleChoiceFilter(
     primary_ip4_id = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_ip4',
         field_name='primary_ip4',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         label=_('Primary IPv4 (ID)'),
         label=_('Primary IPv4 (ID)'),
     )
     )
     primary_ip4 = django_filters.ModelMultipleChoiceFilter(
     primary_ip4 = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_ip4__address',
         field_name='primary_ip4__address',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         to_field_name='address',
         to_field_name='address',
         label=_('Primary IPv4 (address)'),
         label=_('Primary IPv4 (address)'),
     )
     )
     primary_ip6_id = django_filters.ModelMultipleChoiceFilter(
     primary_ip6_id = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_ip6',
         field_name='primary_ip6',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         label=_('Primary IPv6 (ID)'),
         label=_('Primary IPv6 (ID)'),
     )
     )
     primary_ip6 = django_filters.ModelMultipleChoiceFilter(
     primary_ip6 = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_ip6__address',
         field_name='primary_ip6__address',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         to_field_name='address',
         to_field_name='address',
         label=_('Primary IPv6 (address)'),
         label=_('Primary IPv6 (address)'),
     )
     )

+ 9 - 0
netbox/tenancy/filtersets.py

@@ -29,11 +29,13 @@ __all__ = (
 class ContactGroupFilterSet(NestedGroupModelFilterSet):
 class ContactGroupFilterSet(NestedGroupModelFilterSet):
     parent_id = django_filters.ModelMultipleChoiceFilter(
     parent_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
+        distinct=False,
         label=_('Parent contact group (ID)'),
         label=_('Parent contact group (ID)'),
     )
     )
     parent = django_filters.ModelMultipleChoiceFilter(
     parent = django_filters.ModelMultipleChoiceFilter(
         field_name='parent__slug',
         field_name='parent__slug',
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Parent contact group (slug)'),
         label=_('Parent contact group (slug)'),
     )
     )
@@ -113,6 +115,7 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet):
     object_type = MultiValueContentTypeFilter()
     object_type = MultiValueContentTypeFilter()
     contact_id = django_filters.ModelMultipleChoiceFilter(
     contact_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Contact.objects.all(),
         queryset=Contact.objects.all(),
+        distinct=False,
         label=_('Contact (ID)'),
         label=_('Contact (ID)'),
     )
     )
     group_id = TreeNodeMultipleChoiceFilter(
     group_id = TreeNodeMultipleChoiceFilter(
@@ -130,11 +133,13 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet):
     )
     )
     role_id = django_filters.ModelMultipleChoiceFilter(
     role_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ContactRole.objects.all(),
         queryset=ContactRole.objects.all(),
+        distinct=False,
         label=_('Contact role (ID)'),
         label=_('Contact role (ID)'),
     )
     )
     role = django_filters.ModelMultipleChoiceFilter(
     role = django_filters.ModelMultipleChoiceFilter(
         field_name='role__slug',
         field_name='role__slug',
         queryset=ContactRole.objects.all(),
         queryset=ContactRole.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Contact role (slug)'),
         label=_('Contact role (slug)'),
     )
     )
@@ -179,11 +184,13 @@ class ContactModelFilterSet(django_filters.FilterSet):
 class TenantGroupFilterSet(NestedGroupModelFilterSet):
 class TenantGroupFilterSet(NestedGroupModelFilterSet):
     parent_id = django_filters.ModelMultipleChoiceFilter(
     parent_id = django_filters.ModelMultipleChoiceFilter(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
+        distinct=False,
         label=_('Parent tenant group (ID)'),
         label=_('Parent tenant group (ID)'),
     )
     )
     parent = django_filters.ModelMultipleChoiceFilter(
     parent = django_filters.ModelMultipleChoiceFilter(
         field_name='parent__slug',
         field_name='parent__slug',
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Parent tenant group (slug)'),
         label=_('Parent tenant group (slug)'),
     )
     )
@@ -256,10 +263,12 @@ class TenancyFilterSet(django_filters.FilterSet):
     )
     )
     tenant_id = django_filters.ModelMultipleChoiceFilter(
     tenant_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
+        distinct=False,
         label=_('Tenant (ID)'),
         label=_('Tenant (ID)'),
     )
     )
     tenant = django_filters.ModelMultipleChoiceFilter(
     tenant = django_filters.ModelMultipleChoiceFilter(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
+        distinct=False,
         field_name='tenant__slug',
         field_name='tenant__slug',
         to_field_name='slug',
         to_field_name='slug',
         label=_('Tenant (slug)'),
         label=_('Tenant (slug)'),

+ 4 - 0
netbox/users/filterset_mixins.py

@@ -14,22 +14,26 @@ class OwnerFilterMixin(django_filters.FilterSet):
     """
     """
     owner_group_id = django_filters.ModelMultipleChoiceFilter(
     owner_group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=OwnerGroup.objects.all(),
         queryset=OwnerGroup.objects.all(),
+        distinct=False,
         field_name='owner__group',
         field_name='owner__group',
         label=_('Owner Group (ID)'),
         label=_('Owner Group (ID)'),
     )
     )
     owner_group = django_filters.ModelMultipleChoiceFilter(
     owner_group = django_filters.ModelMultipleChoiceFilter(
         queryset=OwnerGroup.objects.all(),
         queryset=OwnerGroup.objects.all(),
+        distinct=False,
         field_name='owner__group__name',
         field_name='owner__group__name',
         to_field_name='name',
         to_field_name='name',
         label=_('Owner Group (name)'),
         label=_('Owner Group (name)'),
     )
     )
     owner_id = django_filters.ModelMultipleChoiceFilter(
     owner_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Owner.objects.all(),
         queryset=Owner.objects.all(),
+        distinct=False,
         label=_('Owner (ID)'),
         label=_('Owner (ID)'),
     )
     )
     owner = django_filters.ModelMultipleChoiceFilter(
     owner = django_filters.ModelMultipleChoiceFilter(
         field_name='owner__name',
         field_name='owner__name',
         queryset=Owner.objects.all(),
         queryset=Owner.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Owner (name)'),
         label=_('Owner (name)'),
     )
     )

+ 4 - 0
netbox/users/filtersets.py

@@ -131,11 +131,13 @@ class TokenFilterSet(BaseFilterSet):
     user_id = django_filters.ModelMultipleChoiceFilter(
     user_id = django_filters.ModelMultipleChoiceFilter(
         field_name='user',
         field_name='user',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         label=_('User'),
         label=_('User'),
     )
     )
     user = django_filters.ModelMultipleChoiceFilter(
     user = django_filters.ModelMultipleChoiceFilter(
         field_name='user__username',
         field_name='user__username',
         queryset=User.objects.all(),
         queryset=User.objects.all(),
+        distinct=False,
         to_field_name='username',
         to_field_name='username',
         label=_('User (name)'),
         label=_('User (name)'),
     )
     )
@@ -280,11 +282,13 @@ class OwnerFilterSet(BaseFilterSet):
     )
     )
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=OwnerGroup.objects.all(),
         queryset=OwnerGroup.objects.all(),
+        distinct=False,
         label=_('Group (ID)'),
         label=_('Group (ID)'),
     )
     )
     group = django_filters.ModelMultipleChoiceFilter(
     group = django_filters.ModelMultipleChoiceFilter(
         field_name='group__name',
         field_name='group__name',
         queryset=OwnerGroup.objects.all(),
         queryset=OwnerGroup.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Group (name)'),
         label=_('Group (name)'),
     )
     )

+ 28 - 0
netbox/virtualization/filtersets.py

@@ -49,26 +49,31 @@ class ClusterGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet)
 class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ScopedFilterSet, ContactModelFilterSet):
 class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ScopedFilterSet, ContactModelFilterSet):
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
+        distinct=False,
         label=_('Parent group (ID)'),
         label=_('Parent group (ID)'),
     )
     )
     group = django_filters.ModelMultipleChoiceFilter(
     group = django_filters.ModelMultipleChoiceFilter(
         field_name='group__slug',
         field_name='group__slug',
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Parent group (slug)'),
         label=_('Parent group (slug)'),
     )
     )
     type_id = django_filters.ModelMultipleChoiceFilter(
     type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
+        distinct=False,
         label=_('Cluster type (ID)'),
         label=_('Cluster type (ID)'),
     )
     )
     type = django_filters.ModelMultipleChoiceFilter(
     type = django_filters.ModelMultipleChoiceFilter(
         field_name='type__slug',
         field_name='type__slug',
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Cluster type (slug)'),
         label=_('Cluster type (slug)'),
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=ClusterStatusChoices,
         choices=ClusterStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
 
 
@@ -96,51 +101,61 @@ class VirtualMachineFilterSet(
 ):
 ):
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=VirtualMachineStatusChoices,
         choices=VirtualMachineStatusChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     start_on_boot = django_filters.MultipleChoiceFilter(
     start_on_boot = django_filters.MultipleChoiceFilter(
         choices=VirtualMachineStartOnBootChoices,
         choices=VirtualMachineStartOnBootChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     cluster_group_id = django_filters.ModelMultipleChoiceFilter(
     cluster_group_id = django_filters.ModelMultipleChoiceFilter(
         field_name='cluster__group',
         field_name='cluster__group',
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
+        distinct=False,
         label=_('Cluster group (ID)'),
         label=_('Cluster group (ID)'),
     )
     )
     cluster_group = django_filters.ModelMultipleChoiceFilter(
     cluster_group = django_filters.ModelMultipleChoiceFilter(
         field_name='cluster__group__slug',
         field_name='cluster__group__slug',
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Cluster group (slug)'),
         label=_('Cluster group (slug)'),
     )
     )
     cluster_type_id = django_filters.ModelMultipleChoiceFilter(
     cluster_type_id = django_filters.ModelMultipleChoiceFilter(
         field_name='cluster__type',
         field_name='cluster__type',
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
+        distinct=False,
         label=_('Cluster type (ID)'),
         label=_('Cluster type (ID)'),
     )
     )
     cluster_type = django_filters.ModelMultipleChoiceFilter(
     cluster_type = django_filters.ModelMultipleChoiceFilter(
         field_name='cluster__type__slug',
         field_name='cluster__type__slug',
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Cluster type (slug)'),
         label=_('Cluster type (slug)'),
     )
     )
     cluster_id = django_filters.ModelMultipleChoiceFilter(
     cluster_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
+        distinct=False,
         label=_('Cluster (ID)'),
         label=_('Cluster (ID)'),
     )
     )
     cluster = django_filters.ModelMultipleChoiceFilter(
     cluster = django_filters.ModelMultipleChoiceFilter(
         field_name='cluster__name',
         field_name='cluster__name',
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Cluster'),
         label=_('Cluster'),
     )
     )
     device_id = django_filters.ModelMultipleChoiceFilter(
     device_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
+        distinct=False,
         label=_('Device (ID)'),
         label=_('Device (ID)'),
     )
     )
     device = django_filters.ModelMultipleChoiceFilter(
     device = django_filters.ModelMultipleChoiceFilter(
         field_name='device__name',
         field_name='device__name',
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Device'),
         label=_('Device'),
     )
     )
@@ -172,11 +187,13 @@ class VirtualMachineFilterSet(
     )
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
     site_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         label=_('Site (ID)'),
         label=_('Site (ID)'),
     )
     )
     site = django_filters.ModelMultipleChoiceFilter(
     site = django_filters.ModelMultipleChoiceFilter(
         field_name='site__slug',
         field_name='site__slug',
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Site (slug)'),
         label=_('Site (slug)'),
     )
     )
@@ -218,6 +235,7 @@ class VirtualMachineFilterSet(
     )
     )
     config_template_id = django_filters.ModelMultipleChoiceFilter(
     config_template_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ConfigTemplate.objects.all(),
         queryset=ConfigTemplate.objects.all(),
+        distinct=False,
         label=_('Config template (ID)'),
         label=_('Config template (ID)'),
     )
     )
 
 
@@ -260,33 +278,39 @@ class VMInterfaceFilterSet(CommonInterfaceFilterSet, OwnerFilterMixin, NetBoxMod
     cluster_id = django_filters.ModelMultipleChoiceFilter(
     cluster_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine__cluster',
         field_name='virtual_machine__cluster',
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
+        distinct=False,
         label=_('Cluster (ID)'),
         label=_('Cluster (ID)'),
     )
     )
     cluster = django_filters.ModelMultipleChoiceFilter(
     cluster = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine__cluster__name',
         field_name='virtual_machine__cluster__name',
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Cluster'),
         label=_('Cluster'),
     )
     )
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine',
         field_name='virtual_machine',
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
+        distinct=False,
         label=_('Virtual machine (ID)'),
         label=_('Virtual machine (ID)'),
     )
     )
     virtual_machine = django_filters.ModelMultipleChoiceFilter(
     virtual_machine = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine__name',
         field_name='virtual_machine__name',
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Virtual machine'),
         label=_('Virtual machine'),
     )
     )
     parent_id = django_filters.ModelMultipleChoiceFilter(
     parent_id = django_filters.ModelMultipleChoiceFilter(
         field_name='parent',
         field_name='parent',
         queryset=VMInterface.objects.all(),
         queryset=VMInterface.objects.all(),
+        distinct=False,
         label=_('Parent interface (ID)'),
         label=_('Parent interface (ID)'),
     )
     )
     bridge_id = django_filters.ModelMultipleChoiceFilter(
     bridge_id = django_filters.ModelMultipleChoiceFilter(
         field_name='bridge',
         field_name='bridge',
         queryset=VMInterface.objects.all(),
         queryset=VMInterface.objects.all(),
+        distinct=False,
         label=_('Bridged interface (ID)'),
         label=_('Bridged interface (ID)'),
     )
     )
     mac_address = MultiValueMACAddressFilter(
     mac_address = MultiValueMACAddressFilter(
@@ -296,11 +320,13 @@ class VMInterfaceFilterSet(CommonInterfaceFilterSet, OwnerFilterMixin, NetBoxMod
     primary_mac_address_id = django_filters.ModelMultipleChoiceFilter(
     primary_mac_address_id = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_mac_address',
         field_name='primary_mac_address',
         queryset=MACAddress.objects.all(),
         queryset=MACAddress.objects.all(),
+        distinct=False,
         label=_('Primary MAC address (ID)'),
         label=_('Primary MAC address (ID)'),
     )
     )
     primary_mac_address = django_filters.ModelMultipleChoiceFilter(
     primary_mac_address = django_filters.ModelMultipleChoiceFilter(
         field_name='primary_mac_address__mac_address',
         field_name='primary_mac_address__mac_address',
         queryset=MACAddress.objects.all(),
         queryset=MACAddress.objects.all(),
+        distinct=False,
         to_field_name='mac_address',
         to_field_name='mac_address',
         label=_('Primary MAC address'),
         label=_('Primary MAC address'),
     )
     )
@@ -323,11 +349,13 @@ class VirtualDiskFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
     virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine',
         field_name='virtual_machine',
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
+        distinct=False,
         label=_('Virtual machine (ID)'),
         label=_('Virtual machine (ID)'),
     )
     )
     virtual_machine = django_filters.ModelMultipleChoiceFilter(
     virtual_machine = django_filters.ModelMultipleChoiceFilter(
         field_name='virtual_machine__name',
         field_name='virtual_machine__name',
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Virtual machine'),
         label=_('Virtual machine'),
     )
     )

+ 42 - 13
netbox/vpn/filtersets.py

@@ -38,28 +38,34 @@ class TunnelGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
 @register_filterset
 @register_filterset
 class TunnelFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
 class TunnelFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
-        choices=TunnelStatusChoices
+        choices=TunnelStatusChoices,
+        distinct=False,
     )
     )
     group_id = django_filters.ModelMultipleChoiceFilter(
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=TunnelGroup.objects.all(),
         queryset=TunnelGroup.objects.all(),
+        distinct=False,
         label=_('Tunnel group (ID)'),
         label=_('Tunnel group (ID)'),
     )
     )
     group = django_filters.ModelMultipleChoiceFilter(
     group = django_filters.ModelMultipleChoiceFilter(
         field_name='group__slug',
         field_name='group__slug',
         queryset=TunnelGroup.objects.all(),
         queryset=TunnelGroup.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('Tunnel group (slug)'),
         label=_('Tunnel group (slug)'),
     )
     )
     encapsulation = django_filters.MultipleChoiceFilter(
     encapsulation = django_filters.MultipleChoiceFilter(
-        choices=TunnelEncapsulationChoices
+        choices=TunnelEncapsulationChoices,
+        distinct=False,
     )
     )
     ipsec_profile_id = django_filters.ModelMultipleChoiceFilter(
     ipsec_profile_id = django_filters.ModelMultipleChoiceFilter(
         queryset=IPSecProfile.objects.all(),
         queryset=IPSecProfile.objects.all(),
+        distinct=False,
         label=_('IPSec profile (ID)'),
         label=_('IPSec profile (ID)'),
     )
     )
     ipsec_profile = django_filters.ModelMultipleChoiceFilter(
     ipsec_profile = django_filters.ModelMultipleChoiceFilter(
         field_name='ipsec_profile__name',
         field_name='ipsec_profile__name',
         queryset=IPSecProfile.objects.all(),
         queryset=IPSecProfile.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('IPSec profile (name)'),
         label=_('IPSec profile (name)'),
     )
     )
@@ -83,16 +89,19 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet):
     tunnel_id = django_filters.ModelMultipleChoiceFilter(
     tunnel_id = django_filters.ModelMultipleChoiceFilter(
         field_name='tunnel',
         field_name='tunnel',
         queryset=Tunnel.objects.all(),
         queryset=Tunnel.objects.all(),
+        distinct=False,
         label=_('Tunnel (ID)'),
         label=_('Tunnel (ID)'),
     )
     )
     tunnel = django_filters.ModelMultipleChoiceFilter(
     tunnel = django_filters.ModelMultipleChoiceFilter(
         field_name='tunnel__name',
         field_name='tunnel__name',
         queryset=Tunnel.objects.all(),
         queryset=Tunnel.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('Tunnel (name)'),
         label=_('Tunnel (name)'),
     )
     )
     role = django_filters.MultipleChoiceFilter(
     role = django_filters.MultipleChoiceFilter(
-        choices=TunnelTerminationRoleChoices
+        choices=TunnelTerminationRoleChoices,
+        distinct=False,
     )
     )
     termination_type = MultiValueContentTypeFilter()
     termination_type = MultiValueContentTypeFilter()
     interface = django_filters.ModelMultipleChoiceFilter(
     interface = django_filters.ModelMultipleChoiceFilter(
@@ -120,6 +129,7 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet):
     outside_ip_id = django_filters.ModelMultipleChoiceFilter(
     outside_ip_id = django_filters.ModelMultipleChoiceFilter(
         field_name='outside_ip',
         field_name='outside_ip',
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
+        distinct=False,
         label=_('Outside IP (ID)'),
         label=_('Outside IP (ID)'),
     )
     )
 
 
@@ -142,16 +152,20 @@ class IKEProposalFilterSet(PrimaryModelFilterSet):
         label=_('IKE policy (name)'),
         label=_('IKE policy (name)'),
     )
     )
     authentication_method = django_filters.MultipleChoiceFilter(
     authentication_method = django_filters.MultipleChoiceFilter(
-        choices=AuthenticationMethodChoices
+        choices=AuthenticationMethodChoices,
+        distinct=False,
     )
     )
     encryption_algorithm = django_filters.MultipleChoiceFilter(
     encryption_algorithm = django_filters.MultipleChoiceFilter(
-        choices=EncryptionAlgorithmChoices
+        choices=EncryptionAlgorithmChoices,
+        distinct=False,
     )
     )
     authentication_algorithm = django_filters.MultipleChoiceFilter(
     authentication_algorithm = django_filters.MultipleChoiceFilter(
-        choices=AuthenticationAlgorithmChoices
+        choices=AuthenticationAlgorithmChoices,
+        distinct=False,
     )
     )
     group = django_filters.MultipleChoiceFilter(
     group = django_filters.MultipleChoiceFilter(
-        choices=DHGroupChoices
+        choices=DHGroupChoices,
+        distinct=False,
     )
     )
 
 
     class Meta:
     class Meta:
@@ -171,10 +185,12 @@ class IKEProposalFilterSet(PrimaryModelFilterSet):
 @register_filterset
 @register_filterset
 class IKEPolicyFilterSet(PrimaryModelFilterSet):
 class IKEPolicyFilterSet(PrimaryModelFilterSet):
     version = django_filters.MultipleChoiceFilter(
     version = django_filters.MultipleChoiceFilter(
-        choices=IKEVersionChoices
+        choices=IKEVersionChoices,
+        distinct=False,
     )
     )
     mode = django_filters.MultipleChoiceFilter(
     mode = django_filters.MultipleChoiceFilter(
-        choices=IKEModeChoices
+        choices=IKEModeChoices,
+        distinct=False,
     )
     )
     ike_proposal_id = django_filters.ModelMultipleChoiceFilter(
     ike_proposal_id = django_filters.ModelMultipleChoiceFilter(
         field_name='proposals',
         field_name='proposals',
@@ -214,10 +230,12 @@ class IPSecProposalFilterSet(PrimaryModelFilterSet):
         label=_('IPSec policy (name)'),
         label=_('IPSec policy (name)'),
     )
     )
     encryption_algorithm = django_filters.MultipleChoiceFilter(
     encryption_algorithm = django_filters.MultipleChoiceFilter(
-        choices=EncryptionAlgorithmChoices
+        choices=EncryptionAlgorithmChoices,
+        distinct=False,
     )
     )
     authentication_algorithm = django_filters.MultipleChoiceFilter(
     authentication_algorithm = django_filters.MultipleChoiceFilter(
-        choices=AuthenticationAlgorithmChoices
+        choices=AuthenticationAlgorithmChoices,
+        distinct=False,
     )
     )
 
 
     class Meta:
     class Meta:
@@ -237,7 +255,8 @@ class IPSecProposalFilterSet(PrimaryModelFilterSet):
 @register_filterset
 @register_filterset
 class IPSecPolicyFilterSet(PrimaryModelFilterSet):
 class IPSecPolicyFilterSet(PrimaryModelFilterSet):
     pfs_group = django_filters.MultipleChoiceFilter(
     pfs_group = django_filters.MultipleChoiceFilter(
-        choices=DHGroupChoices
+        choices=DHGroupChoices,
+        distinct=False,
     )
     )
     ipsec_proposal_id = django_filters.ModelMultipleChoiceFilter(
     ipsec_proposal_id = django_filters.ModelMultipleChoiceFilter(
         field_name='proposals',
         field_name='proposals',
@@ -266,25 +285,30 @@ class IPSecPolicyFilterSet(PrimaryModelFilterSet):
 @register_filterset
 @register_filterset
 class IPSecProfileFilterSet(PrimaryModelFilterSet):
 class IPSecProfileFilterSet(PrimaryModelFilterSet):
     mode = django_filters.MultipleChoiceFilter(
     mode = django_filters.MultipleChoiceFilter(
-        choices=IPSecModeChoices
+        choices=IPSecModeChoices,
+        distinct=False,
     )
     )
     ike_policy_id = django_filters.ModelMultipleChoiceFilter(
     ike_policy_id = django_filters.ModelMultipleChoiceFilter(
         queryset=IKEPolicy.objects.all(),
         queryset=IKEPolicy.objects.all(),
+        distinct=False,
         label=_('IKE policy (ID)'),
         label=_('IKE policy (ID)'),
     )
     )
     ike_policy = django_filters.ModelMultipleChoiceFilter(
     ike_policy = django_filters.ModelMultipleChoiceFilter(
         field_name='ike_policy__name',
         field_name='ike_policy__name',
         queryset=IKEPolicy.objects.all(),
         queryset=IKEPolicy.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('IKE policy (name)'),
         label=_('IKE policy (name)'),
     )
     )
     ipsec_policy_id = django_filters.ModelMultipleChoiceFilter(
     ipsec_policy_id = django_filters.ModelMultipleChoiceFilter(
         queryset=IPSecPolicy.objects.all(),
         queryset=IPSecPolicy.objects.all(),
+        distinct=False,
         label=_('IPSec policy (ID)'),
         label=_('IPSec policy (ID)'),
     )
     )
     ipsec_policy = django_filters.ModelMultipleChoiceFilter(
     ipsec_policy = django_filters.ModelMultipleChoiceFilter(
         field_name='ipsec_policy__name',
         field_name='ipsec_policy__name',
         queryset=IPSecPolicy.objects.all(),
         queryset=IPSecPolicy.objects.all(),
+        distinct=False,
         to_field_name='name',
         to_field_name='name',
         label=_('IPSec policy (name)'),
         label=_('IPSec policy (name)'),
     )
     )
@@ -307,10 +331,12 @@ class IPSecProfileFilterSet(PrimaryModelFilterSet):
 class L2VPNFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
 class L2VPNFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
     type = django_filters.MultipleChoiceFilter(
     type = django_filters.MultipleChoiceFilter(
         choices=L2VPNTypeChoices,
         choices=L2VPNTypeChoices,
+        distinct=False,
         null_value=None
         null_value=None
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
         choices=L2VPNStatusChoices,
         choices=L2VPNStatusChoices,
+        distinct=False,
     )
     )
     import_target_id = django_filters.ModelMultipleChoiceFilter(
     import_target_id = django_filters.ModelMultipleChoiceFilter(
         field_name='import_targets',
         field_name='import_targets',
@@ -354,11 +380,13 @@ class L2VPNFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilter
 class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
 class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
     l2vpn_id = django_filters.ModelMultipleChoiceFilter(
     l2vpn_id = django_filters.ModelMultipleChoiceFilter(
         queryset=L2VPN.objects.all(),
         queryset=L2VPN.objects.all(),
+        distinct=False,
         label=_('L2VPN (ID)'),
         label=_('L2VPN (ID)'),
     )
     )
     l2vpn = django_filters.ModelMultipleChoiceFilter(
     l2vpn = django_filters.ModelMultipleChoiceFilter(
         field_name='l2vpn__slug',
         field_name='l2vpn__slug',
         queryset=L2VPN.objects.all(),
         queryset=L2VPN.objects.all(),
+        distinct=False,
         to_field_name='slug',
         to_field_name='slug',
         label=_('L2VPN (slug)'),
         label=_('L2VPN (slug)'),
     )
     )
@@ -443,6 +471,7 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
     )
     )
     assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
     assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
+        distinct=False,
         field_name='assigned_object_type'
         field_name='assigned_object_type'
     )
     )
     assigned_object_type = MultiValueContentTypeFilter()
     assigned_object_type = MultiValueContentTypeFilter()

+ 21 - 10
netbox/wireless/filtersets.py

@@ -22,11 +22,13 @@ __all__ = (
 @register_filterset
 @register_filterset
 class WirelessLANGroupFilterSet(NestedGroupModelFilterSet):
 class WirelessLANGroupFilterSet(NestedGroupModelFilterSet):
     parent_id = django_filters.ModelMultipleChoiceFilter(
     parent_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=WirelessLANGroup.objects.all()
+        queryset=WirelessLANGroup.objects.all(),
+        distinct=False,
     )
     )
     parent = django_filters.ModelMultipleChoiceFilter(
     parent = django_filters.ModelMultipleChoiceFilter(
         field_name='parent__slug',
         field_name='parent__slug',
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
+        distinct=False,
         to_field_name='slug'
         to_field_name='slug'
     )
     )
     ancestor_id = TreeNodeMultipleChoiceFilter(
     ancestor_id = TreeNodeMultipleChoiceFilter(
@@ -60,20 +62,24 @@ class WirelessLANFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilter
         to_field_name='slug'
         to_field_name='slug'
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
-        choices=WirelessLANStatusChoices
+        choices=WirelessLANStatusChoices,
+        distinct=False,
     )
     )
     vlan_id = django_filters.ModelMultipleChoiceFilter(
     vlan_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=VLAN.objects.all()
+        queryset=VLAN.objects.all(),
+        distinct=False,
     )
     )
     interface_id = django_filters.ModelMultipleChoiceFilter(
     interface_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Interface.objects.all(),
         queryset=Interface.objects.all(),
         field_name='interfaces'
         field_name='interfaces'
     )
     )
     auth_type = django_filters.MultipleChoiceFilter(
     auth_type = django_filters.MultipleChoiceFilter(
-        choices=WirelessAuthTypeChoices
+        choices=WirelessAuthTypeChoices,
+        distinct=False,
     )
     )
     auth_cipher = django_filters.MultipleChoiceFilter(
     auth_cipher = django_filters.MultipleChoiceFilter(
-        choices=WirelessAuthCipherChoices
+        choices=WirelessAuthCipherChoices,
+        distinct=False,
     )
     )
 
 
     class Meta:
     class Meta:
@@ -93,19 +99,24 @@ class WirelessLANFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilter
 @register_filterset
 @register_filterset
 class WirelessLinkFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
 class WirelessLinkFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
     interface_a_id = django_filters.ModelMultipleChoiceFilter(
     interface_a_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=Interface.objects.all()
+        queryset=Interface.objects.all(),
+        distinct=False,
     )
     )
     interface_b_id = django_filters.ModelMultipleChoiceFilter(
     interface_b_id = django_filters.ModelMultipleChoiceFilter(
-        queryset=Interface.objects.all()
+        queryset=Interface.objects.all(),
+        distinct=False,
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
-        choices=LinkStatusChoices
+        choices=LinkStatusChoices,
+        distinct=False,
     )
     )
     auth_type = django_filters.MultipleChoiceFilter(
     auth_type = django_filters.MultipleChoiceFilter(
-        choices=WirelessAuthTypeChoices
+        choices=WirelessAuthTypeChoices,
+        distinct=False,
     )
     )
     auth_cipher = django_filters.MultipleChoiceFilter(
     auth_cipher = django_filters.MultipleChoiceFilter(
-        choices=WirelessAuthCipherChoices
+        choices=WirelessAuthCipherChoices,
+        distinct=False,
     )
     )
 
 
     class Meta:
     class Meta:

Some files were not shown because too many files changed in this diff