Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions netbox/dcim/migrations/0226_modulebay_rebuild_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.db import migrations
import mptt.managers
import mptt.models


def rebuild_mptt(apps, schema_editor):
"""
Rebuild the MPTT tree for ModuleBay to apply new ordering.
"""
ModuleBay = apps.get_model('dcim', 'ModuleBay')

# Set MPTTMeta with the correct order_insertion_by
class MPTTMeta:
order_insertion_by = ('module', 'name',)

ModuleBay.MPTTMeta = MPTTMeta
ModuleBay._mptt_meta = mptt.models.MPTTOptions(MPTTMeta)

manager = mptt.managers.TreeManager()
manager.model = ModuleBay
manager.contribute_to_class(ModuleBay, 'objects')
manager.rebuild()


class Migration(migrations.Migration):
dependencies = [
('dcim', '0225_gfk_indexes'),
]

operations = [
migrations.RunPython(code=rebuild_mptt, reverse_code=migrations.RunPython.noop),
]
2 changes: 1 addition & 1 deletion netbox/dcim/models/device_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ class Meta(ModularComponentModel.Meta):
verbose_name_plural = _('module bays')

class MPTTMeta:
order_insertion_by = ('module',)
order_insertion_by = ('module', 'name',)

def clean(self):
super().clean()
Expand Down
52 changes: 36 additions & 16 deletions netbox/dcim/models/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.db.models.signals import post_save
from django.utils.translation import gettext_lazy as _
from jsonschema.exceptions import ValidationError as JSONValidationError
from mptt.models import MPTTModel

from dcim.choices import *
from dcim.utils import update_interface_bridges
Expand Down Expand Up @@ -329,7 +330,13 @@ def save(self, *args, **kwargs):
component._location = self.device.location
component._rack = self.device.rack

if component_model is not ModuleBay:
if issubclass(component_model, MPTTModel):
# MPTT models must be saved individually to maintain tree structure
# Use delay_mptt_updates for better performance
with component_model.objects.delay_mptt_updates():
for instance in create_instances:
instance.save()
else:
component_model.objects.bulk_create(create_instances)
# Emit the post_save signal for each newly created object
for component in create_instances:
Expand All @@ -341,23 +348,36 @@ def save(self, *args, **kwargs):
using='default',
update_fields=None
)
else:
# ModuleBays must be saved individually for MPTT
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 issubclass(component_model, MPTTModel):
# MPTT models must be saved individually to maintain tree structure
# Use delay_mptt_updates for better performance - could do bulk_update
# but then would need to rebuild the tree after the updates.
with component_model.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
)
else:
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
)

# Interface bridges have to be set after interface instantiation
update_interface_bridges(self.device, self.module_type.interfacetemplates, self)
15 changes: 12 additions & 3 deletions netbox/netbox/views/generic/bulk_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,9 +895,18 @@ def post(self, request):
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):
Expand Down
Loading