mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 00:28:16 -06:00
Enable MPTT for module bays
This commit is contained in:
parent
f8d99ffe5e
commit
6372d065be
@ -496,12 +496,18 @@ class ModuleType(NetBoxObjectType):
|
|||||||
|
|
||||||
@strawberry_django.type(
|
@strawberry_django.type(
|
||||||
models.ModuleBay,
|
models.ModuleBay,
|
||||||
fields='__all__',
|
# fields='__all__',
|
||||||
|
exclude=('parent',),
|
||||||
filters=ModuleBayFilter
|
filters=ModuleBayFilter
|
||||||
)
|
)
|
||||||
class ModuleBayType(ModularComponentType):
|
class ModuleBayType(ModularComponentType):
|
||||||
|
|
||||||
installed_module: Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')] | None
|
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(
|
@strawberry_django.type(
|
||||||
|
44
netbox/dcim/migrations/0191_modulebay_mptt.py
Normal file
44
netbox/dcim/migrations/0191_modulebay_mptt.py
Normal 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,
|
||||||
|
),
|
||||||
|
]
|
@ -4,7 +4,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
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.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from mptt.models import MPTTModel, TreeForeignKey
|
||||||
@ -1087,10 +1087,19 @@ class RearPort(ModularComponentModel, CabledObjectModel, TrackingModelMixin):
|
|||||||
# Bays
|
# Bays
|
||||||
#
|
#
|
||||||
|
|
||||||
class ModuleBay(ModularComponentModel, TrackingModelMixin):
|
class ModuleBay(ModularComponentModel, TrackingModelMixin, MPTTModel):
|
||||||
"""
|
"""
|
||||||
An empty space within a Device which can house a child device
|
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(
|
position = models.CharField(
|
||||||
verbose_name=_('position'),
|
verbose_name=_('position'),
|
||||||
max_length=30,
|
max_length=30,
|
||||||
@ -1098,6 +1107,8 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
|
|||||||
help_text=_('Identifier to reference when renaming installed components')
|
help_text=_('Identifier to reference when renaming installed components')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
objects = TreeManager()
|
||||||
|
|
||||||
clone_fields = ('device',)
|
clone_fields = ('device',)
|
||||||
|
|
||||||
class Meta(ModularComponentModel.Meta):
|
class Meta(ModularComponentModel.Meta):
|
||||||
@ -1110,6 +1121,9 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
|
|||||||
verbose_name = _('module bay')
|
verbose_name = _('module bay')
|
||||||
verbose_name_plural = _('module bays')
|
verbose_name_plural = _('module bays')
|
||||||
|
|
||||||
|
class MPTTMeta:
|
||||||
|
order_insertion_by = ('module',)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:modulebay', kwargs={'pk': self.pk})
|
return reverse('dcim:modulebay', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
@ -1127,6 +1141,11 @@ class ModuleBay(ModularComponentModel, TrackingModelMixin):
|
|||||||
module_bays.append(module.module_bay.pk)
|
module_bays.append(module.module_bay.pk)
|
||||||
module = module.module_bay.module if module.module_bay else None
|
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):
|
class DeviceBay(ComponentModel, TrackingModelMixin):
|
||||||
"""
|
"""
|
||||||
|
@ -1046,7 +1046,8 @@ class Device(
|
|||||||
self._instantiate_components(self.device_type.interfacetemplates.all())
|
self._instantiate_components(self.device_type.interfacetemplates.all())
|
||||||
self._instantiate_components(self.device_type.rearporttemplates.all())
|
self._instantiate_components(self.device_type.rearporttemplates.all())
|
||||||
self._instantiate_components(self.device_type.frontporttemplates.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())
|
self._instantiate_components(self.device_type.devicebaytemplates.all())
|
||||||
# Disable bulk_create to accommodate MPTT
|
# Disable bulk_create to accommodate MPTT
|
||||||
self._instantiate_components(self.device_type.inventoryitemtemplates.all(), bulk_create=False)
|
self._instantiate_components(self.device_type.inventoryitemtemplates.all(), bulk_create=False)
|
||||||
@ -1269,17 +1270,19 @@ class Module(PrimaryModel, ConfigContextModel):
|
|||||||
if not disable_replication:
|
if not disable_replication:
|
||||||
create_instances.append(template_instance)
|
create_instances.append(template_instance)
|
||||||
|
|
||||||
component_model.objects.bulk_create(create_instances)
|
# component_model.objects.bulk_create(create_instances)
|
||||||
# Emit the post_save signal for each newly created object
|
# # Emit the post_save signal for each newly created object
|
||||||
for component in create_instances:
|
# for component in create_instances:
|
||||||
post_save.send(
|
# post_save.send(
|
||||||
sender=component_model,
|
# sender=component_model,
|
||||||
instance=component,
|
# instance=component,
|
||||||
created=True,
|
# created=True,
|
||||||
raw=False,
|
# raw=False,
|
||||||
using='default',
|
# using='default',
|
||||||
update_fields=None
|
# update_fields=None
|
||||||
)
|
# )
|
||||||
|
for instance in create_instances:
|
||||||
|
instance.save()
|
||||||
|
|
||||||
update_fields = ['module']
|
update_fields = ['module']
|
||||||
component_model.objects.bulk_update(update_instances, update_fields)
|
component_model.objects.bulk_update(update_instances, update_fields)
|
||||||
|
@ -313,6 +313,10 @@ class ModularDeviceComponentTable(DeviceComponentTable):
|
|||||||
verbose_name=_('Inventory Items'),
|
verbose_name=_('Inventory Items'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class Meta(NetBoxTable.Meta):
|
||||||
|
pass
|
||||||
|
# order_by = ('device', 'module', 'name')
|
||||||
|
|
||||||
|
|
||||||
class CableTerminationTable(NetBoxTable):
|
class CableTerminationTable(NetBoxTable):
|
||||||
cable = tables.Column(
|
cable = tables.Column(
|
||||||
@ -852,10 +856,9 @@ class ModuleBayTable(ModularDeviceComponentTable):
|
|||||||
'args': [Accessor('device_id')],
|
'args': [Accessor('device_id')],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
parent_bay = tables.Column(
|
parent = tables.Column(
|
||||||
accessor=tables.A('module__module_bay'),
|
|
||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name=_('Parent Bay')
|
verbose_name=_('Parent'),
|
||||||
)
|
)
|
||||||
installed_module = tables.Column(
|
installed_module = tables.Column(
|
||||||
linkify=True,
|
linkify=True,
|
||||||
@ -878,14 +881,14 @@ class ModuleBayTable(ModularDeviceComponentTable):
|
|||||||
verbose_name=_('Module Status')
|
verbose_name=_('Module Status')
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(ModularDeviceComponentTable.Meta):
|
||||||
model = models.ModuleBay
|
model = models.ModuleBay
|
||||||
fields = (
|
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',
|
'module_serial', 'module_asset_tag', 'description', 'tags',
|
||||||
)
|
)
|
||||||
default_columns = (
|
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):
|
def render_parent_bay(self, value):
|
||||||
@ -896,17 +899,24 @@ class ModuleBayTable(ModularDeviceComponentTable):
|
|||||||
|
|
||||||
|
|
||||||
class DeviceModuleBayTable(ModuleBayTable):
|
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(
|
actions = columns.ActionsColumn(
|
||||||
extra_buttons=MODULEBAY_BUTTONS
|
extra_buttons=MODULEBAY_BUTTONS
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(ModuleBayTable.Meta):
|
||||||
model = models.ModuleBay
|
model = models.ModuleBay
|
||||||
fields = (
|
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',
|
'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):
|
class InventoryItemTable(DeviceComponentTable):
|
||||||
|
Loading…
Reference in New Issue
Block a user