فهرست منبع

feat(views): Add FilterSet support to BulkRenameView

Allow passing a FilterSet to BulkRenameView for consistent behavior with
BulkEditView and BulkDeleteView. Enables the
"Select all N matching query" functionality to expand across the full
queryset. Updates logic to handle PK lists appropriately when editing
all matched objects.

Fixes #20389
Martin Hauser 3 ماه پیش
والد
کامیت
ac7a4ec4a3

+ 8 - 0
netbox/circuits/views.py

@@ -83,6 +83,7 @@ class ProviderBulkEditView(generic.BulkEditView):
 @register_model_view(Provider, 'bulk_rename', path='rename', detail=False)
 class ProviderBulkRenameView(generic.BulkRenameView):
     queryset = Provider.objects.all()
+    filterset = filtersets.ProviderFilterSet
 
 
 @register_model_view(Provider, 'bulk_delete', path='delete', detail=False)
@@ -150,6 +151,7 @@ class ProviderAccountBulkEditView(generic.BulkEditView):
 @register_model_view(ProviderAccount, 'bulk_rename', path='rename', detail=False)
 class ProviderAccountBulkRenameView(generic.BulkRenameView):
     queryset = ProviderAccount.objects.all()
+    filterset = filtersets.ProviderAccountFilterSet
 
 
 @register_model_view(ProviderAccount, 'bulk_delete', path='delete', detail=False)
@@ -226,6 +228,7 @@ class ProviderNetworkBulkEditView(generic.BulkEditView):
 @register_model_view(ProviderNetwork, 'bulk_rename', path='rename', detail=False)
 class ProviderNetworkBulkRenameView(generic.BulkRenameView):
     queryset = ProviderNetwork.objects.all()
+    filterset = filtersets.ProviderNetworkFilterSet
 
 
 @register_model_view(ProviderNetwork, 'bulk_delete', path='delete', detail=False)
@@ -290,6 +293,7 @@ class CircuitTypeBulkEditView(generic.BulkEditView):
 @register_model_view(CircuitType, 'bulk_rename', path='rename', detail=False)
 class CircuitTypeBulkRenameView(generic.BulkRenameView):
     queryset = CircuitType.objects.all()
+    filterset = filtersets.CircuitTypeFilterSet
 
 
 @register_model_view(CircuitType, 'bulk_delete', path='delete', detail=False)
@@ -362,6 +366,7 @@ class CircuitBulkEditView(generic.BulkEditView):
 class CircuitBulkRenameView(generic.BulkRenameView):
     queryset = Circuit.objects.all()
     field_name = 'cid'
+    filterset = filtersets.CircuitFilterSet
 
 
 @register_model_view(Circuit, 'bulk_delete', path='delete', detail=False)
@@ -557,6 +562,7 @@ class CircuitGroupBulkEditView(generic.BulkEditView):
 @register_model_view(CircuitGroup, 'bulk_rename', path='rename', detail=False)
 class CircuitGroupBulkRenameView(generic.BulkRenameView):
     queryset = CircuitGroup.objects.all()
+    filterset = filtersets.CircuitGroupFilterSet
 
 
 @register_model_view(CircuitGroup, 'bulk_delete', path='delete', detail=False)
@@ -672,6 +678,7 @@ class VirtualCircuitTypeBulkEditView(generic.BulkEditView):
 @register_model_view(VirtualCircuitType, 'bulk_rename', path='rename', detail=False)
 class VirtualCircuitTypeBulkRenameView(generic.BulkRenameView):
     queryset = VirtualCircuitType.objects.all()
+    filterset = filtersets.VirtualCircuitTypeFilterSet
 
 
 @register_model_view(VirtualCircuitType, 'bulk_delete', path='delete', detail=False)
@@ -744,6 +751,7 @@ class VirtualCircuitBulkEditView(generic.BulkEditView):
 class VirtualCircuitBulkRenameView(generic.BulkRenameView):
     queryset = VirtualCircuit.objects.all()
     field_name = 'cid'
+    filterset = filtersets.VirtualCircuitFilterSet
 
 
 @register_model_view(VirtualCircuit, 'bulk_delete', path='delete', detail=False)

+ 1 - 0
netbox/core/views.py

@@ -125,6 +125,7 @@ class DataSourceBulkEditView(generic.BulkEditView):
 @register_model_view(DataSource, 'bulk_rename', path='rename', detail=False)
 class DataSourceBulkRenameView(generic.BulkRenameView):
     queryset = DataSource.objects.all()
+    filterset = filtersets.DataSourceFilterSet
 
 
 @register_model_view(DataSource, 'bulk_delete', path='delete', detail=False)

+ 37 - 0
netbox/dcim/tests/test_views.py

@@ -2885,6 +2885,43 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
         self.client.post(self._get_url('bulk_delete'), data)
         self.assertEqual(device.interfaces.count(), 4)  # Child & parent were both deleted
 
+    def test_rename_select_all_spans_pages(self):
+        """
+        Tests the bulk rename functionality for interfaces spanning multiple pages in the UI.
+        """
+        device_name = 'DeviceRename'
+        device = create_test_device(device_name)
+        # Create > default page size (25) so selection spans multiple pages
+        for i in range(37):
+            Interface.objects.create(device=device, name=f'eth{i}')
+
+        self.add_permissions('dcim.change_interface')
+
+        # Filter to this device's interfaces to simulate a real list filter
+        get_qs = {'device_id': Device.objects.get(name=device_name).pk}
+        post_url = f'{self._get_url("bulk_rename")}?device_id={get_qs["device_id"]}'
+
+        # Preview step: ensure 37 selected (not just one page)
+        data = {'_preview': '1', '_all': '1', 'find': 'eth', 'replace': 'xe'}
+        response = self.client.post(post_url, data=data)
+        self.assertHttpStatus(response, 200)
+        self.assertEqual(len(response.context['selected_objects']), 37)
+
+        # Extract pk[] just like the browser would submit on Apply
+        # (either from the form's initial, or from selected_objects)
+        pk_list = response.context['form'].initial.get('pk')
+        if not pk_list:
+            pk_list = [obj.pk for obj in response.context['selected_objects']]
+        pk_list = [str(pk) for pk in pk_list]
+
+        # Apply step: include pk[] in the POST
+        apply_data = {'_apply': '1', '_all': '1', 'find': 'eth', 'replace': 'xe', 'pk': pk_list}
+        response = self.client.post(post_url, data=apply_data)
+
+        # On success the view redirects back to the return URL
+        self.assertHttpStatus(response, 302)
+        self.assertEqual(Interface.objects.filter(device=device, name__startswith='xe').count(), 37)
+
 
 class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
     model = FrontPort

+ 29 - 0
netbox/dcim/views.py

@@ -295,6 +295,7 @@ class RegionBulkEditView(generic.BulkEditView):
 @register_model_view(Region, 'bulk_rename', path='rename', detail=False)
 class RegionBulkRenameView(generic.BulkRenameView):
     queryset = Region.objects.all()
+    filterset = filtersets.RegionFilterSet
 
 
 @register_model_view(Region, 'bulk_delete', path='delete', detail=False)
@@ -426,6 +427,7 @@ class SiteGroupBulkEditView(generic.BulkEditView):
 @register_model_view(SiteGroup, 'bulk_rename', path='rename', detail=False)
 class SiteGroupBulkRenameView(generic.BulkRenameView):
     queryset = SiteGroup.objects.all()
+    filterset = filtersets.SiteGroupFilterSet
 
 
 @register_model_view(SiteGroup, 'bulk_delete', path='delete', detail=False)
@@ -516,6 +518,7 @@ class SiteBulkEditView(generic.BulkEditView):
 @register_model_view(Site, 'bulk_rename', path='rename', detail=False)
 class SiteBulkRenameView(generic.BulkRenameView):
     queryset = Site.objects.all()
+    filterset = filtersets.SiteFilterSet
 
 
 @register_model_view(Site, 'bulk_delete', path='delete', detail=False)
@@ -625,6 +628,7 @@ class LocationBulkEditView(generic.BulkEditView):
 @register_model_view(Location, 'bulk_rename', path='rename', detail=False)
 class LocationBulkRenameView(generic.BulkRenameView):
     queryset = Location.objects.all()
+    filterset = filtersets.LocationFilterSet
 
 
 @register_model_view(Location, 'bulk_delete', path='delete', detail=False)
@@ -695,6 +699,7 @@ class RackRoleBulkEditView(generic.BulkEditView):
 @register_model_view(RackRole, 'bulk_rename', path='rename', detail=False)
 class RackRoleBulkRenameView(generic.BulkRenameView):
     queryset = RackRole.objects.all()
+    filterset = filtersets.RackRoleFilterSet
 
 
 @register_model_view(RackRole, 'bulk_delete', path='delete', detail=False)
@@ -760,6 +765,7 @@ class RackTypeBulkEditView(generic.BulkEditView):
 class RackTypeBulkRenameView(generic.BulkRenameView):
     queryset = RackType.objects.all()
     field_name = 'model'
+    filterset = filtersets.RackTypeFilterSet
 
 
 @register_model_view(RackType, 'bulk_delete', path='delete', detail=False)
@@ -944,6 +950,7 @@ class RackBulkEditView(generic.BulkEditView):
 @register_model_view(Rack, 'bulk_rename', path='rename', detail=False)
 class RackBulkRenameView(generic.BulkRenameView):
     queryset = Rack.objects.all()
+    filterset = filtersets.RackFilterSet
 
 
 @register_model_view(Rack, 'bulk_delete', path='delete', detail=False)
@@ -1083,6 +1090,7 @@ class ManufacturerBulkEditView(generic.BulkEditView):
 @register_model_view(Manufacturer, 'bulk_rename', path='rename', detail=False)
 class ManufacturerBulkRenameView(generic.BulkRenameView):
     queryset = Manufacturer.objects.all()
+    filterset = filtersets.ManufacturerFilterSet
 
 
 @register_model_view(Manufacturer, 'bulk_delete', path='delete', detail=False)
@@ -1336,6 +1344,7 @@ class DeviceTypeBulkEditView(generic.BulkEditView):
 class DeviceTypeBulkRenameView(generic.BulkRenameView):
     queryset = DeviceType.objects.all()
     field_name = 'model'
+    filterset = filtersets.DeviceTypeFilterSet
 
 
 @register_model_view(DeviceType, 'bulk_delete', path='delete', detail=False)
@@ -1397,6 +1406,7 @@ class ModuleTypeProfileBulkEditView(generic.BulkEditView):
 @register_model_view(ModuleTypeProfile, 'bulk_rename', path='rename', detail=False)
 class ModuleTypeProfileBulkRenameView(generic.BulkRenameView):
     queryset = ModuleTypeProfile.objects.all()
+    filterset = filtersets.ModuleTypeProfileFilterSet
 
 
 @register_model_view(ModuleTypeProfile, 'bulk_delete', path='delete', detail=False)
@@ -1612,6 +1622,7 @@ class ModuleTypeBulkEditView(generic.BulkEditView):
 @register_model_view(ModuleType, 'bulk_rename', path='rename', detail=False)
 class ModuleTypeBulkRenameView(generic.BulkRenameView):
     queryset = ModuleType.objects.all()
+    filterset = filtersets.ModuleTypeFilterSet
 
 
 @register_model_view(ModuleType, 'bulk_delete', path='delete', detail=False)
@@ -2100,6 +2111,7 @@ class DeviceRoleBulkEditView(generic.BulkEditView):
 @register_model_view(DeviceRole, 'bulk_rename', path='rename', detail=False)
 class DeviceRoleBulkRenameView(generic.BulkRenameView):
     queryset = DeviceRole.objects.all()
+    filterset = filtersets.DeviceRoleFilterSet
 
 
 @register_model_view(DeviceRole, 'bulk_delete', path='delete', detail=False)
@@ -2175,6 +2187,7 @@ class PlatformBulkEditView(generic.BulkEditView):
 @register_model_view(Platform, 'bulk_rename', path='rename', detail=False)
 class PlatformBulkRenameView(generic.BulkRenameView):
     queryset = Platform.objects.all()
+    filterset = filtersets.PlatformFilterSet
 
 
 @register_model_view(Platform, 'bulk_delete', path='delete', detail=False)
@@ -2582,6 +2595,7 @@ class ConsolePortBulkEditView(generic.BulkEditView):
 @register_model_view(ConsolePort, 'bulk_rename', path='rename', detail=False)
 class ConsolePortBulkRenameView(generic.BulkRenameView):
     queryset = ConsolePort.objects.all()
+    filterset = filtersets.ConsolePortFilterSet
 
 
 @register_model_view(ConsolePort, 'bulk_disconnect', path='disconnect', detail=False)
@@ -2652,6 +2666,7 @@ class ConsoleServerPortBulkEditView(generic.BulkEditView):
 @register_model_view(ConsoleServerPort, 'bulk_rename', path='rename', detail=False)
 class ConsoleServerPortBulkRenameView(generic.BulkRenameView):
     queryset = ConsoleServerPort.objects.all()
+    filterset = filtersets.ConsoleServerPortFilterSet
 
 
 @register_model_view(ConsoleServerPort, 'bulk_disconnect', path='disconnect', detail=False)
@@ -2722,6 +2737,7 @@ class PowerPortBulkEditView(generic.BulkEditView):
 @register_model_view(PowerPort, 'bulk_rename', path='rename', detail=False)
 class PowerPortBulkRenameView(generic.BulkRenameView):
     queryset = PowerPort.objects.all()
+    filterset = filtersets.PowerPortFilterSet
 
 
 @register_model_view(PowerPort, 'bulk_disconnect', path='disconnect', detail=False)
@@ -2792,6 +2808,7 @@ class PowerOutletBulkEditView(generic.BulkEditView):
 @register_model_view(PowerOutlet, 'bulk_rename', path='rename', detail=False)
 class PowerOutletBulkRenameView(generic.BulkRenameView):
     queryset = PowerOutlet.objects.all()
+    filterset = filtersets.PowerOutletFilterSet
 
 
 @register_model_view(PowerOutlet, 'bulk_disconnect', path='disconnect', detail=False)
@@ -2934,6 +2951,7 @@ class InterfaceBulkEditView(generic.BulkEditView):
 @register_model_view(Interface, 'bulk_rename', path='rename', detail=False)
 class InterfaceBulkRenameView(generic.BulkRenameView):
     queryset = Interface.objects.all()
+    filterset = filtersets.InterfaceFilterSet
 
 
 @register_model_view(Interface, 'bulk_disconnect', path='disconnect', detail=False)
@@ -3005,6 +3023,7 @@ class FrontPortBulkEditView(generic.BulkEditView):
 @register_model_view(FrontPort, 'bulk_rename', path='rename', detail=False)
 class FrontPortBulkRenameView(generic.BulkRenameView):
     queryset = FrontPort.objects.all()
+    filterset = filtersets.FrontPortFilterSet
 
 
 @register_model_view(FrontPort, 'bulk_disconnect', path='disconnect', detail=False)
@@ -3080,6 +3099,7 @@ class RearPortBulkRenameView(generic.BulkRenameView):
 @register_model_view(RearPort, 'bulk_disconnect', path='disconnect', detail=False)
 class RearPortBulkDisconnectView(BulkDisconnectView):
     queryset = RearPort.objects.all()
+    filterset = filtersets.RearPortFilterSet
 
 
 @register_model_view(RearPort, 'bulk_delete', path='delete', detail=False)
@@ -3145,6 +3165,7 @@ class ModuleBayBulkEditView(generic.BulkEditView):
 @register_model_view(ModuleBay, 'bulk_rename', path='rename', detail=False)
 class ModuleBayBulkRenameView(generic.BulkRenameView):
     queryset = ModuleBay.objects.all()
+    filterset = filtersets.ModuleBayFilterSet
 
 
 @register_model_view(ModuleBay, 'bulk_delete', path='delete', detail=False)
@@ -3287,6 +3308,7 @@ class DeviceBayBulkEditView(generic.BulkEditView):
 @register_model_view(DeviceBay, 'bulk_rename', path='rename', detail=False)
 class DeviceBayBulkRenameView(generic.BulkRenameView):
     queryset = DeviceBay.objects.all()
+    filterset = filtersets.DeviceBayFilterSet
 
 
 @register_model_view(DeviceBay, 'bulk_delete', path='delete', detail=False)
@@ -3348,6 +3370,7 @@ class InventoryItemBulkEditView(generic.BulkEditView):
 @register_model_view(InventoryItem, 'bulk_rename', path='rename', detail=False)
 class InventoryItemBulkRenameView(generic.BulkRenameView):
     queryset = InventoryItem.objects.all()
+    filterset = filtersets.InventoryItemFilterSet
 
 
 @register_model_view(InventoryItem, 'bulk_delete', path='delete', detail=False)
@@ -3431,6 +3454,7 @@ class InventoryItemRoleBulkEditView(generic.BulkEditView):
 @register_model_view(InventoryItemRole, 'bulk_rename', path='rename', detail=False)
 class InventoryItemRoleBulkRenameView(generic.BulkRenameView):
     queryset = InventoryItemRole.objects.all()
+    filterset = filtersets.InventoryItemRoleFilterSet
 
 
 @register_model_view(InventoryItemRole, 'bulk_delete', path='delete', detail=False)
@@ -3634,6 +3658,7 @@ class CableBulkEditView(generic.BulkEditView):
 class CableBulkRenameView(generic.BulkRenameView):
     queryset = Cable.objects.all()
     field_name = 'label'
+    filterset = filtersets.CableFilterSet
 
 
 @register_model_view(Cable, 'bulk_delete', path='delete', detail=False)
@@ -3931,6 +3956,7 @@ class VirtualChassisBulkEditView(generic.BulkEditView):
 @register_model_view(VirtualChassis, 'bulk_rename', path='rename', detail=False)
 class VirtualChassisBulkRenameView(generic.BulkRenameView):
     queryset = VirtualChassis.objects.all()
+    filterset = filtersets.VirtualChassisFilterSet
 
 
 @register_model_view(VirtualChassis, 'bulk_delete', path='delete', detail=False)
@@ -3993,6 +4019,7 @@ class PowerPanelBulkEditView(generic.BulkEditView):
 @register_model_view(PowerPanel, 'bulk_rename', path='rename', detail=False)
 class PowerPanelBulkRenameView(generic.BulkRenameView):
     queryset = PowerPanel.objects.all()
+    filterset = filtersets.PowerPanelFilterSet
 
 
 @register_model_view(PowerPanel, 'bulk_delete', path='delete', detail=False)
@@ -4050,6 +4077,7 @@ class PowerFeedBulkEditView(generic.BulkEditView):
 @register_model_view(PowerFeed, 'bulk_rename', path='rename', detail=False)
 class PowerFeedBulkRenameView(generic.BulkRenameView):
     queryset = PowerFeed.objects.all()
+    filterset = filtersets.PowerFeedFilterSet
 
 
 @register_model_view(PowerFeed, 'bulk_disconnect', path='disconnect', detail=False)
@@ -4128,6 +4156,7 @@ class VirtualDeviceContextBulkEditView(generic.BulkEditView):
 @register_model_view(VirtualDeviceContext, 'bulk_rename', path='rename', detail=False)
 class VirtualDeviceContextBulkRenameView(generic.BulkRenameView):
     queryset = VirtualDeviceContext.objects.all()
+    filterset = filtersets.VirtualDeviceContextFilterSet
 
 
 @register_model_view(VirtualDeviceContext, 'bulk_delete', path='delete', detail=False)

+ 13 - 0
netbox/extras/views.py

@@ -101,6 +101,7 @@ class CustomFieldBulkEditView(generic.BulkEditView):
 @register_model_view(CustomField, 'bulk_rename', path='rename', detail=False)
 class CustomFieldBulkRenameView(generic.BulkRenameView):
     queryset = CustomField.objects.all()
+    filterset = filtersets.CustomFieldFilterSet
 
 
 @register_model_view(CustomField, 'bulk_delete', path='delete', detail=False)
@@ -175,6 +176,7 @@ class CustomFieldChoiceSetBulkEditView(generic.BulkEditView):
 @register_model_view(CustomFieldChoiceSet, 'bulk_rename', path='rename', detail=False)
 class CustomFieldChoiceSetBulkRenameView(generic.BulkRenameView):
     queryset = CustomFieldChoiceSet.objects.all()
+    filterset = filtersets.CustomFieldChoiceSetFilterSet
 
 
 @register_model_view(CustomFieldChoiceSet, 'bulk_delete', path='delete', detail=False)
@@ -230,6 +232,7 @@ class CustomLinkBulkEditView(generic.BulkEditView):
 @register_model_view(CustomLink, 'bulk_rename', path='rename', detail=False)
 class CustomLinkBulkRenameView(generic.BulkRenameView):
     queryset = CustomLink.objects.all()
+    filterset = filtersets.CustomLinkFilterSet
 
 
 @register_model_view(CustomLink, 'bulk_delete', path='delete', detail=False)
@@ -286,6 +289,7 @@ class ExportTemplateBulkEditView(generic.BulkEditView):
 @register_model_view(ExportTemplate, 'bulk_rename', path='rename', detail=False)
 class ExportTemplateBulkRenameView(generic.BulkRenameView):
     queryset = ExportTemplate.objects.all()
+    filterset = filtersets.ExportTemplateFilterSet
 
 
 @register_model_view(ExportTemplate, 'bulk_delete', path='delete', detail=False)
@@ -351,6 +355,7 @@ class SavedFilterBulkEditView(SharedObjectViewMixin, generic.BulkEditView):
 @register_model_view(SavedFilter, 'bulk_rename', path='rename', detail=False)
 class SavedFilterBulkRenameView(generic.BulkRenameView):
     queryset = SavedFilter.objects.all()
+    filterset = filtersets.SavedFilterFilterSet
 
 
 @register_model_view(SavedFilter, 'bulk_delete', path='delete', detail=False)
@@ -413,6 +418,7 @@ class TableConfigBulkEditView(SharedObjectViewMixin, generic.BulkEditView):
 @register_model_view(TableConfig, 'bulk_rename', path='rename', detail=False)
 class TableConfigBulkRenameView(generic.BulkRenameView):
     queryset = TableConfig.objects.all()
+    filterset = filtersets.TableConfigFilterSet
 
 
 @register_model_view(TableConfig, 'bulk_delete', path='delete', detail=False)
@@ -499,6 +505,7 @@ class NotificationGroupBulkEditView(generic.BulkEditView):
 @register_model_view(NotificationGroup, 'bulk_rename', path='rename', detail=False)
 class NotificationGroupBulkRenameView(generic.BulkRenameView):
     queryset = NotificationGroup.objects.all()
+    filterset = filtersets.NotificationGroupFilterSet
 
 
 @register_model_view(NotificationGroup, 'bulk_delete', path='delete', detail=False)
@@ -650,6 +657,7 @@ class WebhookBulkEditView(generic.BulkEditView):
 @register_model_view(Webhook, 'bulk_rename', path='rename', detail=False)
 class WebhookBulkRenameView(generic.BulkRenameView):
     queryset = Webhook.objects.all()
+    filterset = filtersets.WebhookFilterSet
 
 
 @register_model_view(Webhook, 'bulk_delete', path='delete', detail=False)
@@ -705,6 +713,7 @@ class EventRuleBulkEditView(generic.BulkEditView):
 @register_model_view(EventRule, 'bulk_rename', path='rename', detail=False)
 class EventRuleBulkRenameView(generic.BulkRenameView):
     queryset = EventRule.objects.all()
+    filterset = filtersets.EventRuleFilterSet
 
 
 @register_model_view(EventRule, 'bulk_delete', path='delete', detail=False)
@@ -841,6 +850,7 @@ class ConfigContextProfileBulkEditView(generic.BulkEditView):
 @register_model_view(ConfigContextProfile, 'bulk_rename', path='rename', detail=False)
 class ConfigContextProfileBulkRenameView(generic.BulkRenameView):
     queryset = ConfigContextProfile.objects.all()
+    filterset = filtersets.ConfigContextProfileFilterSet
 
 
 @register_model_view(ConfigContextProfile, 'bulk_delete', path='delete', detail=False)
@@ -929,6 +939,7 @@ class ConfigContextBulkEditView(generic.BulkEditView):
 @register_model_view(ConfigContext, 'bulk_rename', path='rename', detail=False)
 class ConfigContextBulkRenameView(generic.BulkRenameView):
     queryset = ConfigContext.objects.all()
+    filterset = filtersets.ConfigContextFilterSet
 
 
 @register_model_view(ConfigContext, 'bulk_delete', path='delete', detail=False)
@@ -1020,6 +1031,7 @@ class ConfigTemplateBulkEditView(generic.BulkEditView):
 @register_model_view(ConfigTemplate, 'bulk_rename', path='rename', detail=False)
 class ConfigTemplateBulkRenameView(generic.BulkRenameView):
     queryset = ConfigTemplate.objects.all()
+    filterset = filtersets.ConfigTemplateFilterSet
 
 
 @register_model_view(ConfigTemplate, 'bulk_delete', path='delete', detail=False)
@@ -1143,6 +1155,7 @@ class ImageAttachmentBulkEditView(generic.BulkEditView):
 @register_model_view(ImageAttachment, 'bulk_rename', path='rename', detail=False)
 class ImageAttachmentBulkRenameView(generic.BulkRenameView):
     queryset = ImageAttachment.objects.all()
+    filterset = filtersets.ImageAttachmentFilterSet
 
 
 @register_model_view(ImageAttachment, 'bulk_delete', path='delete', detail=False)

+ 13 - 0
netbox/ipam/views.py

@@ -108,6 +108,7 @@ class VRFBulkEditView(generic.BulkEditView):
 @register_model_view(VRF, 'bulk_rename', path='rename', detail=False)
 class VRFBulkRenameView(generic.BulkRenameView):
     queryset = VRF.objects.all()
+    filterset = filtersets.VRFFilterSet
 
 
 @register_model_view(VRF, 'bulk_delete', path='delete', detail=False)
@@ -163,6 +164,7 @@ class RouteTargetBulkEditView(generic.BulkEditView):
 @register_model_view(RouteTarget, 'bulk_rename', path='rename', detail=False)
 class RouteTargetBulkRenameView(generic.BulkRenameView):
     queryset = RouteTarget.objects.all()
+    filterset = filtersets.RouteTargetFilterSet
 
 
 @register_model_view(RouteTarget, 'bulk_delete', path='delete', detail=False)
@@ -227,6 +229,7 @@ class RIRBulkEditView(generic.BulkEditView):
 @register_model_view(RIR, 'bulk_rename', path='rename', detail=False)
 class RIRBulkRenameView(generic.BulkRenameView):
     queryset = RIR.objects.all()
+    filterset = filtersets.RIRFilterSet
 
 
 @register_model_view(RIR, 'bulk_delete', path='delete', detail=False)
@@ -305,6 +308,7 @@ class ASNRangeBulkEditView(generic.BulkEditView):
 @register_model_view(ASNRange, 'bulk_rename', path='rename', detail=False)
 class ASNRangeBulkRenameView(generic.BulkRenameView):
     queryset = ASNRange.objects.all()
+    filterset = filtersets.ASNRangeFilterSet
 
 
 @register_model_view(ASNRange, 'bulk_delete', path='delete', detail=False)
@@ -377,6 +381,7 @@ class ASNBulkEditView(generic.BulkEditView):
 @register_model_view(ASN, 'bulk_rename', path='rename', detail=False)
 class ASNBulkRenameView(generic.BulkRenameView):
     queryset = ASN.objects.all()
+    filterset = filtersets.ASNFilterSet
 
 
 @register_model_view(ASN, 'bulk_delete', path='delete', detail=False)
@@ -536,6 +541,7 @@ class RoleBulkEditView(generic.BulkEditView):
 @register_model_view(Role, 'bulk_rename', path='rename', detail=False)
 class RoleBulkRenameView(generic.BulkRenameView):
     queryset = Role.objects.all()
+    filterset = filtersets.RoleFilterSet
 
 
 @register_model_view(Role, 'bulk_delete', path='delete', detail=False)
@@ -820,6 +826,7 @@ class IPRangeBulkEditView(generic.BulkEditView):
 @register_model_view(IPRange, 'bulk_rename', path='rename', detail=False)
 class IPRangeBulkRenameView(generic.BulkRenameView):
     queryset = IPRange.objects.all()
+    filterset = filtersets.IPRangeFilterSet
 
 
 @register_model_view(IPRange, 'bulk_delete', path='delete', detail=False)
@@ -1066,6 +1073,7 @@ class VLANGroupBulkEditView(generic.BulkEditView):
 @register_model_view(VLANGroup, 'bulk_rename', path='rename', detail=False)
 class VLANGroupBulkRenameView(generic.BulkRenameView):
     queryset = VLANGroup.objects.all()
+    filterset = filtersets.VLANGroupFilterSet
 
 
 @register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False)
@@ -1160,6 +1168,7 @@ class VLANTranslationPolicyBulkEditView(generic.BulkEditView):
 @register_model_view(VLANTranslationPolicy, 'bulk_rename', path='rename', detail=False)
 class VLANTranslationPolicyBulkRenameView(generic.BulkRenameView):
     queryset = VLANTranslationPolicy.objects.all()
+    filterset = filtersets.VLANTranslationPolicyFilterSet
 
 
 @register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False)
@@ -1315,6 +1324,7 @@ class FHRPGroupBulkEditView(generic.BulkEditView):
 @register_model_view(FHRPGroup, 'bulk_rename', path='rename', detail=False)
 class FHRPGroupBulkRenameView(generic.BulkRenameView):
     queryset = FHRPGroup.objects.all()
+    filterset = filtersets.FHRPGroupFilterSet
 
 
 @register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False)
@@ -1447,6 +1457,7 @@ class VLANBulkEditView(generic.BulkEditView):
 @register_model_view(VLAN, 'bulk_rename', path='rename', detail=False)
 class VLANBulkRenameView(generic.BulkRenameView):
     queryset = VLAN.objects.all()
+    filterset = filtersets.VLANFilterSet
 
 
 @register_model_view(VLAN, 'bulk_delete', path='delete', detail=False)
@@ -1502,6 +1513,7 @@ class ServiceTemplateBulkEditView(generic.BulkEditView):
 @register_model_view(ServiceTemplate, 'bulk_rename', path='rename', detail=False)
 class ServiceTemplateBulkRenameView(generic.BulkRenameView):
     queryset = ServiceTemplate.objects.all()
+    filterset = filtersets.ServiceTemplateFilterSet
 
 
 @register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False)
@@ -1574,6 +1586,7 @@ class ServiceBulkEditView(generic.BulkEditView):
 @register_model_view(Service, 'bulk_rename', path='rename', detail=False)
 class ServiceBulkRenameView(generic.BulkRenameView):
     queryset = Service.objects.all()
+    filterset = filtersets.ServiceFilterSet
 
 
 @register_model_view(Service, 'bulk_delete', path='delete', detail=False)

+ 13 - 4
netbox/netbox/views/generic/bulk_views.py

@@ -799,6 +799,9 @@ class BulkRenameView(GetReturnURLMixin, BaseMultiObjectView):
     """
     field_name = 'name'
     template_name = 'generic/bulk_rename.html'
+    # Match BulkEditView/BulkDeleteView behavior: allow passing a FilterSet
+    # so "Select all N matching query" can expand across the full queryset.
+    filterset = None
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -840,9 +843,16 @@ class BulkRenameView(GetReturnURLMixin, BaseMultiObjectView):
     def post(self, request):
         logger = logging.getLogger('netbox.views.BulkRenameView')
 
+        # If we are editing *all* objects in the queryset, replace the PK list with all matched objects.
+        if request.POST.get('_all') and self.filterset is not None:
+            pk_list = self.filterset(request.GET, self.queryset.values_list('pk', flat=True), request=request).qs
+        else:
+            pk_list = request.POST.getlist('pk')
+
+        selected_objects = self.queryset.filter(pk__in=pk_list)
+
         if '_preview' in request.POST or '_apply' in request.POST:
-            form = self.form(request.POST, initial={'pk': request.POST.getlist('pk')})
-            selected_objects = self.queryset.filter(pk__in=form.initial['pk'])
+            form = self.form(request.POST, initial={'pk': pk_list})
 
             if form.is_valid():
                 try:
@@ -877,8 +887,7 @@ class BulkRenameView(GetReturnURLMixin, BaseMultiObjectView):
                     clear_events.send(sender=self)
 
         else:
-            form = self.form(initial={'pk': request.POST.getlist('pk')})
-            selected_objects = self.queryset.filter(pk__in=form.initial['pk'])
+            form = self.form(initial={'pk': pk_list})
 
         return render(request, self.template_name, {
             'field_name': self.field_name,

+ 5 - 0
netbox/tenancy/views.py

@@ -74,6 +74,7 @@ class TenantGroupBulkEditView(generic.BulkEditView):
 @register_model_view(TenantGroup, 'bulk_rename', path='rename', detail=False)
 class TenantGroupBulkRenameView(generic.BulkRenameView):
     queryset = TenantGroup.objects.all()
+    filterset = filtersets.TenantGroupFilterSet
 
 
 @register_model_view(TenantGroup, 'bulk_delete', path='delete', detail=False)
@@ -140,6 +141,7 @@ class TenantBulkEditView(generic.BulkEditView):
 @register_model_view(Tenant, 'bulk_rename', path='rename', detail=False)
 class TenantBulkRenameView(generic.BulkRenameView):
     queryset = Tenant.objects.all()
+    filterset = filtersets.TenantFilterSet
 
 
 @register_model_view(Tenant, 'bulk_delete', path='delete', detail=False)
@@ -220,6 +222,7 @@ class ContactGroupBulkEditView(generic.BulkEditView):
 @register_model_view(ContactGroup, 'bulk_rename', path='rename', detail=False)
 class ContactGroupBulkRenameView(generic.BulkRenameView):
     queryset = ContactGroup.objects.all()
+    filterset = filtersets.ContactGroupFilterSet
 
 
 @register_model_view(ContactGroup, 'bulk_delete', path='delete', detail=False)
@@ -286,6 +289,7 @@ class ContactRoleBulkEditView(generic.BulkEditView):
 @register_model_view(ContactRole, 'bulk_rename', path='rename', detail=False)
 class ContactRoleBulkRenameView(generic.BulkRenameView):
     queryset = ContactRole.objects.all()
+    filterset = filtersets.ContactRoleFilterSet
 
 
 @register_model_view(ContactRole, 'bulk_delete', path='delete', detail=False)
@@ -354,6 +358,7 @@ class ContactBulkEditView(generic.BulkEditView):
 @register_model_view(Contact, 'bulk_rename', path='rename', detail=False)
 class ContactBulkRenameView(generic.BulkRenameView):
     queryset = Contact.objects.all()
+    filterset = filtersets.ContactFilterSet
 
 
 @register_model_view(Contact, 'bulk_delete', path='delete', detail=False)

+ 3 - 0
netbox/users/views.py

@@ -117,6 +117,7 @@ class UserBulkEditView(generic.BulkEditView):
 class UserBulkRenameView(generic.BulkRenameView):
     queryset = User.objects.all()
     field_name = 'username'
+    filterset = filtersets.UserFilterSet
 
 
 @register_model_view(User, 'bulk_delete', path='delete', detail=False)
@@ -173,6 +174,7 @@ class GroupBulkEditView(generic.BulkEditView):
 @register_model_view(Group, 'bulk_rename', path='rename', detail=False)
 class GroupBulkRenameView(generic.BulkRenameView):
     queryset = Group.objects.all()
+    filterset = filtersets.GroupFilterSet
 
 
 @register_model_view(Group, 'bulk_delete', path='delete', detail=False)
@@ -211,6 +213,7 @@ class ObjectPermissionEditView(generic.ObjectEditView):
 @register_model_view(ObjectPermission, 'delete')
 class ObjectPermissionDeleteView(generic.ObjectDeleteView):
     queryset = ObjectPermission.objects.all()
+    filterset = filtersets.ObjectPermissionFilterSet
 
 
 @register_model_view(ObjectPermission, 'bulk_edit', path='edit', detail=False)

+ 6 - 0
netbox/virtualization/views.py

@@ -80,6 +80,7 @@ class ClusterTypeBulkEditView(generic.BulkEditView):
 @register_model_view(ClusterType, 'bulk_rename', path='rename', detail=False)
 class ClusterTypeBulkRenameView(generic.BulkRenameView):
     queryset = ClusterType.objects.all()
+    filterset = filtersets.ClusterTypeFilterSet
 
 
 @register_model_view(ClusterType, 'bulk_delete', path='delete', detail=False)
@@ -158,6 +159,7 @@ class ClusterGroupBulkEditView(generic.BulkEditView):
 @register_model_view(ClusterGroup, 'bulk_rename', path='rename', detail=False)
 class ClusterGroupBulkRenameView(generic.BulkRenameView):
     queryset = ClusterGroup.objects.all()
+    filterset = filtersets.ClusterGroupFilterSet
 
 
 @register_model_view(ClusterGroup, 'bulk_delete', path='delete', detail=False)
@@ -277,6 +279,7 @@ class ClusterBulkEditView(generic.BulkEditView):
 @register_model_view(Cluster, 'bulk_rename', path='rename', detail=False)
 class ClusterBulkRenameView(generic.BulkRenameView):
     queryset = Cluster.objects.all()
+    filterset = filtersets.ClusterFilterSet
 
 
 @register_model_view(Cluster, 'bulk_delete', path='delete', detail=False)
@@ -437,6 +440,7 @@ class VirtualMachineBulkEditView(generic.BulkEditView):
 @register_model_view(VirtualMachine, 'bulk_rename', path='rename', detail=False)
 class VirtualMachineBulkRenameView(generic.BulkRenameView):
     queryset = VirtualMachine.objects.all()
+    filterset = filtersets.VirtualMachineFilterSet
 
 
 @register_model_view(VirtualMachine, 'bulk_delete', path='delete', detail=False)
@@ -539,6 +543,7 @@ class VMInterfaceBulkEditView(generic.BulkEditView):
 @register_model_view(VMInterface, 'bulk_rename', path='rename', detail=False)
 class VMInterfaceBulkRenameView(generic.BulkRenameView):
     queryset = VMInterface.objects.all()
+    filterset = filtersets.VMInterfaceFilterSet
     form = forms.VMInterfaceBulkRenameForm
 
 
@@ -602,6 +607,7 @@ class VirtualDiskBulkEditView(generic.BulkEditView):
 @register_model_view(VirtualDisk, 'bulk_rename', path='rename', detail=False)
 class VirtualDiskBulkRenameView(generic.BulkRenameView):
     queryset = VirtualDisk.objects.all()
+    filterset = filtersets.VirtualDiskFilterSet
     form = forms.VirtualDiskBulkRenameForm
 
 

+ 8 - 0
netbox/vpn/views.py

@@ -62,6 +62,7 @@ class TunnelGroupBulkEditView(generic.BulkEditView):
 @register_model_view(TunnelGroup, 'bulk_rename', path='rename', detail=False)
 class TunnelGroupBulkRenameView(generic.BulkRenameView):
     queryset = TunnelGroup.objects.all()
+    filterset = filtersets.TunnelGroupFilterSet
 
 
 @register_model_view(TunnelGroup, 'bulk_delete', path='delete', detail=False)
@@ -131,6 +132,7 @@ class TunnelBulkEditView(generic.BulkEditView):
 @register_model_view(Tunnel, 'bulk_rename', path='rename', detail=False)
 class TunnelBulkRenameView(generic.BulkRenameView):
     queryset = Tunnel.objects.all()
+    filterset = filtersets.TunnelFilterSet
 
 
 @register_model_view(Tunnel, 'bulk_delete', path='delete', detail=False)
@@ -238,6 +240,7 @@ class IKEProposalBulkEditView(generic.BulkEditView):
 @register_model_view(IKEProposal, 'bulk_rename', path='rename', detail=False)
 class IKEProposalBulkRenameView(generic.BulkRenameView):
     queryset = IKEProposal.objects.all()
+    filterset = filtersets.IKEProposalFilterSet
 
 
 @register_model_view(IKEProposal, 'bulk_delete', path='delete', detail=False)
@@ -293,6 +296,7 @@ class IKEPolicyBulkEditView(generic.BulkEditView):
 @register_model_view(IKEPolicy, 'bulk_rename', path='rename', detail=False)
 class IKEPolicyBulkRenameView(generic.BulkRenameView):
     queryset = IKEPolicy.objects.all()
+    filterset = filtersets.IKEPolicyFilterSet
 
 
 @register_model_view(IKEPolicy, 'bulk_delete', path='delete', detail=False)
@@ -348,6 +352,7 @@ class IPSecProposalBulkEditView(generic.BulkEditView):
 @register_model_view(IPSecProposal, 'bulk_rename', path='rename', detail=False)
 class IPSecProposalBulkRenameView(generic.BulkRenameView):
     queryset = IPSecProposal.objects.all()
+    filterset = filtersets.IPSecProposalFilterSet
 
 
 @register_model_view(IPSecProposal, 'bulk_delete', path='delete', detail=False)
@@ -403,6 +408,7 @@ class IPSecPolicyBulkEditView(generic.BulkEditView):
 @register_model_view(IPSecPolicy, 'bulk_rename', path='rename', detail=False)
 class IPSecPolicyBulkRenameView(generic.BulkRenameView):
     queryset = IPSecPolicy.objects.all()
+    filterset = filtersets.IPSecPolicyFilterSet
 
 
 @register_model_view(IPSecPolicy, 'bulk_delete', path='delete', detail=False)
@@ -458,6 +464,7 @@ class IPSecProfileBulkEditView(generic.BulkEditView):
 @register_model_view(IPSecProfile, 'bulk_rename', path='rename', detail=False)
 class IPSecProfileBulkRenameView(generic.BulkRenameView):
     queryset = IPSecProfile.objects.all()
+    filterset = filtersets.IPSecProfileFilterSet
 
 
 @register_model_view(IPSecProfile, 'bulk_delete', path='delete', detail=False)
@@ -530,6 +537,7 @@ class L2VPNBulkEditView(generic.BulkEditView):
 @register_model_view(L2VPN, 'bulk_rename', path='rename', detail=False)
 class L2VPNBulkRenameView(generic.BulkRenameView):
     queryset = L2VPN.objects.all()
+    filterset = filtersets.L2VPNFilterSet
 
 
 @register_model_view(L2VPN, 'bulk_delete', path='delete', detail=False)

+ 3 - 0
netbox/wireless/views.py

@@ -71,6 +71,7 @@ class WirelessLANGroupBulkEditView(generic.BulkEditView):
 @register_model_view(WirelessLANGroup, 'bulk_rename', path='rename', detail=False)
 class WirelessLANGroupBulkRenameView(generic.BulkRenameView):
     queryset = WirelessLANGroup.objects.all()
+    filterset = filtersets.WirelessLANGroupFilterSet
 
 
 @register_model_view(WirelessLANGroup, 'bulk_delete', path='delete', detail=False)
@@ -146,6 +147,7 @@ class WirelessLANBulkEditView(generic.BulkEditView):
 class WirelessLANBulkRenameView(generic.BulkRenameView):
     queryset = WirelessLAN.objects.all()
     field_name = 'ssid'
+    filterset = filtersets.WirelessLANFilterSet
 
 
 @register_model_view(WirelessLAN, 'bulk_delete', path='delete', detail=False)
@@ -202,6 +204,7 @@ class WirelessLinkBulkEditView(generic.BulkEditView):
 class WirelessLinkBulkRenameView(generic.BulkRenameView):
     queryset = WirelessLink.objects.all()
     field_name = 'ssid'
+    filterset = filtersets.WirelessLinkFilterSet
 
 
 @register_model_view(WirelessLink, 'bulk_delete', path='delete', detail=False)