diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index ad1e29f26..c1222f63f 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1100,6 +1100,10 @@ class DeviceFilterSet( queryset=IPAddress.objects.all(), label=_('OOB IP (ID)'), ) + has_virtual_device_contexts = django_filters.BooleanFilter( + method='_has_virtual_device_contexts', + label=_('Has virtual device contexts'), + ) class Meta: model = Device @@ -1176,6 +1180,12 @@ class DeviceFilterSet( def _device_bays(self, queryset, name, value): return queryset.exclude(devicebays__isnull=value) + def _has_virtual_device_contexts(self, queryset, name, value): + params = Q(vdcs__isnull=False) + if value: + return queryset.filter(params).distinct() + return queryset.exclude(params) + class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet, PrimaryIPFilterSet): device_id = django_filters.ModelMultipleChoiceFilter( diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 21854b53f..6aea4f26e 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -657,6 +657,7 @@ class DeviceFilterForm( ), FieldSet( 'has_primary_ip', 'has_oob_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data', + 'has_virtual_device_contexts', name=_('Miscellaneous') ) ) @@ -813,6 +814,13 @@ class DeviceFilterForm( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) + has_virtual_device_contexts = forms.NullBooleanField( + required=False, + label=_('Has virtual device contexts'), + widget=forms.Select( + choices=BOOLEAN_WITH_BLANK_CHOICES + ) + ) tag = TagFilterField(model)