diff --git a/netbox/dcim/forms/object_import.py b/netbox/dcim/forms/object_import.py index 9df029386..cc0c7dc41 100644 --- a/netbox/dcim/forms/object_import.py +++ b/netbox/dcim/forms/object_import.py @@ -50,23 +50,21 @@ class ModuleTypeImportForm(BootstrapMixin, forms.ModelForm): class ComponentTemplateImportForm(BootstrapMixin, forms.ModelForm): - def __init__(self, device_type, data=None, *args, **kwargs): - - # Must pass the parent DeviceType on form initialization - data.update({ - 'device_type': device_type.pk, - }) - - super().__init__(data, *args, **kwargs) - def clean_device_type(self): - - data = self.cleaned_data['device_type'] - # Limit fields referencing other components to the parent DeviceType - for field_name, field in self.fields.items(): - if isinstance(field, forms.ModelChoiceField) and field_name != 'device_type': - field.queryset = field.queryset.filter(device_type=data) + if data := self.cleaned_data['device_type']: + for field_name, field in self.fields.items(): + if isinstance(field, forms.ModelChoiceField) and field_name not in ['device_type', 'module_type']: + field.queryset = field.queryset.filter(device_type=data) + + return data + + def clean_module_type(self): + # Limit fields referencing other components to the parent ModuleType + if data := self.cleaned_data['module_type']: + for field_name, field in self.fields.items(): + if isinstance(field, forms.ModelChoiceField) and field_name not in ['device_type', 'module_type']: + field.queryset = field.queryset.filter(module_type=data) return data @@ -76,7 +74,7 @@ class ConsolePortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = ConsolePortTemplate fields = [ - 'device_type', 'name', 'label', 'type', 'description', + 'device_type', 'module_type', 'name', 'label', 'type', 'description', ] @@ -85,7 +83,7 @@ class ConsoleServerPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = ConsoleServerPortTemplate fields = [ - 'device_type', 'name', 'label', 'type', 'description', + 'device_type', 'module_type', 'name', 'label', 'type', 'description', ] @@ -94,7 +92,7 @@ class PowerPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = PowerPortTemplate fields = [ - 'device_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', + 'device_type', 'module_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', ] @@ -108,7 +106,7 @@ class PowerOutletTemplateImportForm(ComponentTemplateImportForm): class Meta: model = PowerOutletTemplate fields = [ - 'device_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', + 'device_type', 'module_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', ] @@ -120,7 +118,7 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm): class Meta: model = InterfaceTemplate fields = [ - 'device_type', 'name', 'label', 'type', 'mgmt_only', 'description', + 'device_type', 'module_type', 'name', 'label', 'type', 'mgmt_only', 'description', ] @@ -136,7 +134,7 @@ class FrontPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = FrontPortTemplate fields = [ - 'device_type', 'name', 'type', 'rear_port', 'rear_port_position', 'label', 'description', + 'device_type', 'module_type', 'name', 'type', 'rear_port', 'rear_port_position', 'label', 'description', ] @@ -148,7 +146,7 @@ class RearPortTemplateImportForm(ComponentTemplateImportForm): class Meta: model = RearPortTemplate fields = [ - 'device_type', 'name', 'type', 'positions', 'label', 'description', + 'device_type', 'module_type', 'name', 'type', 'positions', 'label', 'description', ] diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 15e7d2406..f673e64d5 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -892,6 +892,10 @@ class DeviceTypeImportView(generic.ObjectImportView): ('device-bays', forms.DeviceBayTemplateImportForm), )) + def prep_related_object_data(self, parent, data): + data.update({'device_type': parent}) + return data + class DeviceTypeBulkEditView(generic.BulkEditView): queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( @@ -1009,6 +1013,10 @@ class ModuleTypeImportView(generic.ObjectImportView): ('front-ports', forms.FrontPortTemplateImportForm), )) + def prep_related_object_data(self, parent, data): + data.update({'module_type': parent}) + return data + class ModuleTypeBulkEditView(generic.BulkEditView): queryset = ModuleType.objects.prefetch_related('manufacturer').annotate( diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 588b51062..eda3658a6 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -319,6 +319,13 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): def get_required_permission(self): return get_permission_for_model(self.queryset.model, 'add') + def prep_related_object_data(self, parent, data): + """ + Hook to modify the data for related objects before it's passed to the related object form (for example, to + assign a parent object). + """ + return data + def _create_object(self, model_form): # Save the primary object @@ -333,8 +340,8 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): related_obj_pks = [] for i, rel_obj_data in enumerate(model_form.data.get(field_name, list())): - - f = related_object_form(obj, rel_obj_data) + rel_obj_data = self.prep_related_object_data(obj, rel_obj_data) + f = related_object_form(rel_obj_data) for subfield_name, field in f.fields.items(): if subfield_name not in rel_obj_data and hasattr(field, 'initial'):