diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 8d27baab9..e01c3f658 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1350,6 +1350,19 @@ class ModuleFilterSet(NetBoxModelFilterSet): to_field_name='slug', label=_('Region (slug)'), ) + site_group_id = TreeNodeMultipleChoiceFilter( + queryset=SiteGroup.objects.all(), + field_name='device__site__group', + lookup_expr='in', + label=_('Site group (ID)'), + ) + site_group = TreeNodeMultipleChoiceFilter( + queryset=SiteGroup.objects.all(), + field_name='device__site__group', + lookup_expr='in', + to_field_name='slug', + label=_('Site group (slug)'), + ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='device__site', queryset=Site.objects.all(), diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index d491bdaf8..5d5d25f96 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -940,7 +940,7 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo model = Module fieldsets = ( FieldSet('q', 'filter_id', 'tag'), - FieldSet('region_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), + FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), FieldSet('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')), ) device_id = DynamicModelMultipleChoiceField( @@ -958,6 +958,11 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo required=False, label=_('Region') ) + site_group_id = DynamicModelMultipleChoiceField( + queryset=SiteGroup.objects.all(), + required=False, + label=_('Site group') + ) site_id = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), required=False, diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index 363778734..3fa44927d 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -2737,10 +2737,18 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests): for region in regions: region.save() + groups = ( + SiteGroup(name='Site Group 1', slug='site-group-1'), + SiteGroup(name='Site Group 2', slug='site-group-2'), + SiteGroup(name='Site Group 3', slug='site-group-3'), + ) + for group in groups: + group.save() + sites = Site.objects.bulk_create(( - Site(name='Site 1', slug='site-1', region=regions[0]), - Site(name='Site 2', slug='site-2', region=regions[1]), - Site(name='Site 3', slug='site-3', region=regions[2]), + Site(name='Site 1', slug='site-1', region=regions[0], group=groups[0]), + Site(name='Site 2', slug='site-2', region=regions[1], group=groups[1]), + Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) @@ -2964,6 +2972,13 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'region': [regions[0].slug, regions[1].slug]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) + def test_site_group(self): + site_groups = SiteGroup.objects.all()[:2] + params = {'site_group_id': [site_groups[0].pk, site_groups[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) + params = {'site_group': [site_groups[0].slug, site_groups[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) + def test_site(self): sites = Site.objects.all()[:2] params = {'site_id': [sites[0].pk, sites[1].pk]}