diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 3b136987d..e5e4f805f 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -638,13 +638,20 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): ) def instantiate(self, **kwargs): - parent = InventoryItem.objects.get(name=self.parent.name, **kwargs) if self.parent else None + # if instance_map this means this is instantiating from a template, so need to map + # parent pointers to their previously instanced object and not the template one + instance_map = kwargs.pop('instance_map', None) + if self.parent and instance_map and self.parent.name in instance_map: + parent = instance_map[self.parent.name] + else: + parent = InventoryItem.objects.get(name=self.parent.name, **kwargs) if self.parent else None + if self.component: model = self.component.component_model component = model.objects.get(name=self.component.name, **kwargs) else: component = None - return self.component_model( + obj = self.component_model( parent=parent, name=self.name, label=self.label, @@ -654,3 +661,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): part_id=self.part_id, **kwargs ) + if instance_map is not None: + instance_map[self.name] = obj + + return obj diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 1429003c5..fa8080494 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -766,15 +766,21 @@ class Device(PrimaryModel, ConfigContextModel): 'vc_position': "A device assigned to a virtual chassis must have its position defined." }) - def _instantiate_components(self, queryset, bulk_create=True): + def _instantiate_components(self, queryset, bulk_create=True, from_template=False): """ Instantiate components for the device from the specified component templates. Args: bulk_create: If True, bulk_create() will be called to create all components in a single query (default). Otherwise, save() will be called on each instance individually. + from_template: If True will create an instance map to map parent-child template ids + to the newly created instances. """ - components = [obj.instantiate(device=self) for obj in queryset] + instance_map = None + if from_template: + instance_map = {} + + components = [obj.instantiate(device=self, instance_map=instance_map) for obj in queryset] if components and bulk_create: model = components[0]._meta.model model.objects.bulk_create(components) @@ -816,7 +822,7 @@ class Device(PrimaryModel, ConfigContextModel): self._instantiate_components(self.device_type.modulebaytemplates.all()) 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) + self._instantiate_components(self.device_type.inventoryitemtemplates.all(), bulk_create=False, from_template=True) # Update Site and Rack assignment for any child Devices devices = Device.objects.filter(parent_bay__device=self)