diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index bdbaf9f18..3f016899e 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -18,7 +18,6 @@ from .common import ModuleCommonForm __all__ = ( 'CableImportForm', - 'ChildDeviceImportForm', 'ConsolePortImportForm', 'ConsoleServerPortImportForm', 'DeviceBayImportForm', @@ -413,6 +412,18 @@ class DeviceImportForm(BaseDeviceImportForm): required=False, help_text=_('Mounted rack face') ) + parent = CSVModelChoiceField( + queryset=Device.objects.all(), + to_field_name='name', + required=False, + help_text=_('Parent device (for child devices)') + ) + device_bay = CSVModelChoiceField( + queryset=DeviceBay.objects.all(), + to_field_name='name', + required=False, + help_text=_('Device bay in which this device is installed (for child devices)') + ) airflow = CSVChoiceField( choices=DeviceAirflowChoices, required=False, @@ -422,8 +433,8 @@ class DeviceImportForm(BaseDeviceImportForm): class Meta(BaseDeviceImportForm.Meta): fields = [ 'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status', - 'site', 'location', 'rack', 'position', 'face', 'airflow', 'virtual_chassis', 'vc_position', 'vc_priority', - 'cluster', 'description', 'comments', 'tags', + 'site', 'location', 'rack', 'position', 'face', 'parent', 'device_bay', 'airflow', 'virtual_chassis', + 'vc_position', 'vc_priority', 'cluster', 'description', 'comments', 'tags', ] def __init__(self, data=None, *args, **kwargs): @@ -434,6 +445,7 @@ class DeviceImportForm(BaseDeviceImportForm): # Limit location queryset by assigned site params = {f"site__{self.fields['site'].to_field_name}": data.get('site')} self.fields['location'].queryset = self.fields['location'].queryset.filter(**params) + self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params) # Limit rack queryset by assigned site and group params = { @@ -442,6 +454,23 @@ class DeviceImportForm(BaseDeviceImportForm): } self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params) + # Limit device bay queryset by parent device + if parent := data.get('parent'): + params = {f"device__{self.fields['parent'].to_field_name}": parent} + self.fields['device_bay'].queryset = self.fields['device_bay'].queryset.filter(**params) + + def clean(self): + super().clean() + + # Inherit site and rack from parent device + if parent := self.cleaned_data.get('parent'): + self.instance.site = parent.site + self.instance.rack = parent.rack + + # Set parent_bay reverse relationship + if device_bay := self.cleaned_data.get('device_bay'): + self.instance.parent_bay = device_bay + class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm): device = CSVModelChoiceField( @@ -495,48 +524,6 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm): return self.cleaned_data['replicate_components'] -class ChildDeviceImportForm(BaseDeviceImportForm): - parent = CSVModelChoiceField( - queryset=Device.objects.all(), - to_field_name='name', - help_text=_('Parent device') - ) - device_bay = CSVModelChoiceField( - queryset=DeviceBay.objects.all(), - to_field_name='name', - help_text=_('Device bay in which this device is installed') - ) - - class Meta(BaseDeviceImportForm.Meta): - fields = [ - 'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status', - 'parent', 'device_bay', 'virtual_chassis', 'vc_position', 'vc_priority', 'cluster', 'comments', 'tags' - ] - - def __init__(self, data=None, *args, **kwargs): - super().__init__(data, *args, **kwargs) - - if data: - - # Limit device bay queryset by parent device - params = {f"device__{self.fields['parent'].to_field_name}": data.get('parent')} - self.fields['device_bay'].queryset = self.fields['device_bay'].queryset.filter(**params) - - def clean(self): - super().clean() - - # Set parent_bay reverse relationship - device_bay = self.cleaned_data.get('device_bay') - if device_bay: - self.instance.parent_bay = device_bay - - # Inherit site and rack from parent device - parent = self.cleaned_data.get('parent') - if parent: - self.instance.site = parent.site - self.instance.rack = parent.rack - - # # Device components # diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 6772f96ad..c71a0aff1 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -177,7 +177,6 @@ urlpatterns = [ path('devices/', views.DeviceListView.as_view(), name='device_list'), path('devices/add/', views.DeviceEditView.as_view(), name='device_add'), path('devices/import/', views.DeviceBulkImportView.as_view(), name='device_import'), - path('devices/import/child-devices/', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'), path('devices/edit/', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'), path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'), path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 46d12937b..0643ac739 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2090,22 +2090,15 @@ class DeviceBulkImportView(generic.BulkImportView): queryset = Device.objects.all() model_form = forms.DeviceImportForm table = tables.DeviceImportTable - template_name = 'dcim/device_import.html' - - -class ChildDeviceBulkImportView(generic.BulkImportView): - queryset = Device.objects.all() - model_form = forms.ChildDeviceImportForm - table = tables.DeviceImportTable - template_name = 'dcim/device_import_child.html' def save_object(self, object_form, request): obj = object_form.save() - # Save the reverse relation to the parent device bay - device_bay = obj.parent_bay - device_bay.installed_device = obj - device_bay.save() + # For child devices, save the reverse relation to the parent device bay + if getattr(obj, 'parent_bay', None): + device_bay = obj.parent_bay + device_bay.installed_device = obj + device_bay.save() return obj diff --git a/netbox/templates/dcim/device_import.html b/netbox/templates/dcim/device_import.html deleted file mode 100644 index b30de60c2..000000000 --- a/netbox/templates/dcim/device_import.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'generic/bulk_import.html' %} - -{% block tabs %} - {% include 'dcim/inc/device_import_header.html' %} -{% endblock %} diff --git a/netbox/templates/dcim/device_import_child.html b/netbox/templates/dcim/device_import_child.html deleted file mode 100644 index d0dc72b61..000000000 --- a/netbox/templates/dcim/device_import_child.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends 'generic/bulk_import.html' %} - -{% block tabs %} - {% include 'dcim/inc/device_import_header.html' with active_tab='child_import' %} -{% endblock %} diff --git a/netbox/templates/dcim/inc/device_import_header.html b/netbox/templates/dcim/inc/device_import_header.html deleted file mode 100644 index 97e849c2a..000000000 --- a/netbox/templates/dcim/inc/device_import_header.html +++ /dev/null @@ -1,8 +0,0 @@ -