Enable MPTT for module bays

This commit is contained in:
Jeremy Stretch 2024-08-02 16:08:05 -04:00
parent f8d99ffe5e
commit 6372d065be
5 changed files with 106 additions and 24 deletions

View File

@ -496,12 +496,18 @@ class ModuleType(NetBoxObjectType):
@strawberry_django.type(
models.ModuleBay,
fields='__all__',
# fields='__all__',
exclude=('parent',),
filters=ModuleBayFilter
)
class ModuleBayType(ModularComponentType):
installed_module: Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')] | None
children: List[Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')]]
@strawberry_django.field
def parent(self) -> Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')] | None:
return self.parent
@strawberry_django.type(

View File

@ -0,0 +1,44 @@
# Generated by Django 5.0.7 on 2024-08-02 20:07
import django.db.models.deletion
import mptt.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0190_nested_modules'),
]
operations = [
migrations.AddField(
model_name='modulebay',
name='level',
field=models.PositiveIntegerField(default=0, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='modulebay',
name='lft',
field=models.PositiveIntegerField(default=0, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='modulebay',
name='parent',
field=mptt.fields.TreeForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dcim.modulebay'),
),
migrations.AddField(
model_name='modulebay',
name='rght',
field=models.PositiveIntegerField(default=0, editable=False),
preserve_default=False,
),
migrations.AddField(
model_name='modulebay',
name='tree_id',
field=models.PositiveIntegerField(db_index=True, default=0, editable=False),
preserve_default=False,
),
]

View File

@ -4,7 +4,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import Sum
from django.db.models import F, Sum
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from mptt.models import MPTTModel, TreeForeignKey
@ -1087,10 +1087,19 @@ class RearPort(ModularComponentModel, CabledObjectModel, TrackingModelMixin):
# Bays
#
class ModuleBay(ModularComponentModel, TrackingModelMixin):
class ModuleBay(ModularComponentModel, TrackingModelMixin, MPTTModel):
"""
An empty space within a Device which can house a child device
"""
parent = TreeForeignKey(
to='self',
on_delete=models.CASCADE,
related_name='children',
blank=True,
null=True,
editable=False,
db_index=True
)
position = models.CharField(
verbose_name=_('position'),
max_length=30,
@ -1098,6 +1107,8 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
help_text=_('Identifier to reference when renaming installed components')
)
objects = TreeManager()
clone_fields = ('device',)
class Meta(ModularComponentModel.Meta):
@ -1110,6 +1121,9 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
verbose_name = _('module bay')
verbose_name_plural = _('module bays')
class MPTTMeta:
order_insertion_by = ('module',)
def get_absolute_url(self):
return reverse('dcim:modulebay', kwargs={'pk': self.pk})
@ -1127,6 +1141,11 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
module_bays.append(module.module_bay.pk)
module = module.module_bay.module if module.module_bay else None
def save(self, *args, **kwargs):
if self.module:
self.parent = self.module.module_bay
super().save(*args, **kwargs)
class DeviceBay(ComponentModel, TrackingModelMixin):
"""

View File

@ -1046,7 +1046,8 @@ class Device(
self._instantiate_components(self.device_type.interfacetemplates.all())
self._instantiate_components(self.device_type.rearporttemplates.all())
self._instantiate_components(self.device_type.frontporttemplates.all())
self._instantiate_components(self.device_type.modulebaytemplates.all())
# Disable bulk_create to accommodate MPTT
self._instantiate_components(self.device_type.modulebaytemplates.all(), bulk_create=False)
self._instantiate_components(self.device_type.devicebaytemplates.all())
# Disable bulk_create to accommodate MPTT
self._instantiate_components(self.device_type.inventoryitemtemplates.all(), bulk_create=False)
@ -1269,17 +1270,19 @@ class Module(PrimaryModel, ConfigContextModel):
if not disable_replication:
create_instances.append(template_instance)
component_model.objects.bulk_create(create_instances)
# Emit the post_save signal for each newly created object
for component in create_instances:
post_save.send(
sender=component_model,
instance=component,
created=True,
raw=False,
using='default',
update_fields=None
)
# component_model.objects.bulk_create(create_instances)
# # Emit the post_save signal for each newly created object
# for component in create_instances:
# post_save.send(
# sender=component_model,
# instance=component,
# created=True,
# raw=False,
# using='default',
# update_fields=None
# )
for instance in create_instances:
instance.save()
update_fields = ['module']
component_model.objects.bulk_update(update_instances, update_fields)

View File

@ -313,6 +313,10 @@ class ModularDeviceComponentTable(DeviceComponentTable):
verbose_name=_('Inventory Items'),
)
class Meta(NetBoxTable.Meta):
pass
# order_by = ('device', 'module', 'name')
class CableTerminationTable(NetBoxTable):
cable = tables.Column(
@ -852,10 +856,9 @@ class ModuleBayTable(ModularDeviceComponentTable):
'args': [Accessor('device_id')],
}
)
parent_bay = tables.Column(
accessor=tables.A('module__module_bay'),
parent = tables.Column(
linkify=True,
verbose_name=_('Parent Bay')
verbose_name=_('Parent'),
)
installed_module = tables.Column(
linkify=True,
@ -878,14 +881,14 @@ class ModuleBayTable(ModularDeviceComponentTable):
verbose_name=_('Module Status')
)
class Meta(DeviceComponentTable.Meta):
class Meta(ModularDeviceComponentTable.Meta):
model = models.ModuleBay
fields = (
'pk', 'id', 'name', 'device', 'parent_bay', 'label', 'position', 'installed_module', 'module_status',
'pk', 'id', 'name', 'device', 'parent', 'label', 'position', 'installed_module', 'module_status',
'module_serial', 'module_asset_tag', 'description', 'tags',
)
default_columns = (
'pk', 'name', 'device', 'parent_bay', 'label', 'installed_module', 'module_status', 'description',
'pk', 'name', 'device', 'parent', 'label', 'installed_module', 'module_status', 'description',
)
def render_parent_bay(self, value):
@ -896,17 +899,24 @@ class ModuleBayTable(ModularDeviceComponentTable):
class DeviceModuleBayTable(ModuleBayTable):
name = tables.TemplateColumn(
verbose_name=_('Name'),
template_code='<a href="{{ record.get_absolute_url }}" style="padding-left: {{ record.level }}0px">'
'{{ value }}</a>',
order_by=Accessor('_name'),
attrs={'td': {'class': 'text-nowrap'}}
)
actions = columns.ActionsColumn(
extra_buttons=MODULEBAY_BUTTONS
)
class Meta(DeviceComponentTable.Meta):
class Meta(ModuleBayTable.Meta):
model = models.ModuleBay
fields = (
'pk', 'id', 'parent_bay', 'name', 'label', 'position', 'installed_module', 'module_status', 'module_serial',
'pk', 'id', 'parent', 'name', 'label', 'position', 'installed_module', 'module_status', 'module_serial',
'module_asset_tag', 'description', 'tags', 'actions',
)
default_columns = ('pk', 'parent_bay', 'name', 'label', 'installed_module', 'module_status', 'description')
default_columns = ('pk', 'name', 'label', 'installed_module', 'module_status', 'description')
class InventoryItemTable(DeviceComponentTable):