Arthur 1 месяц назад
Родитель
Сommit
be1a008216

+ 1 - 1
netbox/dcim/models/device_components.py

@@ -1273,7 +1273,7 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin, MPTTModel):
         verbose_name_plural = _('module bays')
 
     class MPTTMeta:
-        order_insertion_by = ('name',)
+        order_insertion_by = ('module', 'name',)
 
     def clean(self):
         super().clean()

+ 34 - 13
netbox/dcim/models/modules.py

@@ -343,21 +343,42 @@ class Module(TrackingModelMixin, PrimaryModel, ConfigContextModel):
                     )
             else:
                 # ModuleBays must be saved individually for MPTT
-                for instance in create_instances:
-                    instance.save()
+                # Use delay_mptt_updates for better performance when creating multiple ModuleBays
+                with ModuleBay.objects.delay_mptt_updates():
+                    for instance in create_instances:
+                        instance.save()
 
             update_fields = ['module']
-            component_model.objects.bulk_update(update_instances, update_fields)
-            # Emit the post_save signal for each updated object
-            for component in update_instances:
-                post_save.send(
-                    sender=component_model,
-                    instance=component,
-                    created=False,
-                    raw=False,
-                    using='default',
-                    update_fields=update_fields
-                )
+
+            if component_model is not ModuleBay:
+                component_model.objects.bulk_update(update_instances, update_fields)
+                # Emit the post_save signal for each updated object
+                for component in update_instances:
+                    post_save.send(
+                        sender=component_model,
+                        instance=component,
+                        created=False,
+                        raw=False,
+                        using='default',
+                        update_fields=update_fields
+                    )
+            else:
+                # ModuleBays must be saved individually to maintain MPTT tree structure
+                # Use delay_mptt_updates for better performance
+                with ModuleBay.objects.delay_mptt_updates():
+                    for component in update_instances:
+                        component.save()
+                        post_save.send(
+                            sender=component_model,
+                            instance=component,
+                            created=False,
+                            raw=False,
+                            using='default',
+                            update_fields=update_fields
+                        )
+                # Rebuild the tree once to apply order_insertion_by after all operations
+                if create_instances or update_instances:
+                    ModuleBay.objects.rebuild()
 
         # Interface bridges have to be set after interface instantiation
         update_interface_bridges(self.device, self.module_type.interfacetemplates, self)

+ 12 - 3
netbox/netbox/views/generic/bulk_views.py

@@ -895,9 +895,18 @@ class BulkRenameView(GetReturnURLMixin, BaseMultiObjectView):
                         renamed_pks = self._rename_objects(form, selected_objects)
 
                         if '_apply' in request.POST:
-                            for obj in selected_objects:
-                                setattr(obj, self.field_name, obj.new_name)
-                                obj.save()
+                            # For MPTT models, delay tree updates until all saves are complete
+                            if issubclass(self.queryset.model, MPTTModel):
+                                with self.queryset.model.objects.delay_mptt_updates():
+                                    for obj in selected_objects:
+                                        setattr(obj, self.field_name, obj.new_name)
+                                        obj.save()
+                                # Rebuild the tree to apply order_insertion_by after renaming
+                                self.queryset.model.objects.rebuild()
+                            else:
+                                for obj in selected_objects:
+                                    setattr(obj, self.field_name, obj.new_name)
+                                    obj.save()
 
                             # Enforce constrained permissions
                             if self.queryset.filter(pk__in=renamed_pks).count() != len(selected_objects):