Fixes #11528: Permit import of devices using uploaded file

This commit is contained in:
jeremystretch 2023-01-25 09:55:45 -05:00
parent d5ccda355f
commit b8de9c0875
6 changed files with 37 additions and 76 deletions

View File

@ -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
#

View File

@ -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'),

View File

@ -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

View File

@ -1,5 +0,0 @@
{% extends 'generic/bulk_import.html' %}
{% block tabs %}
{% include 'dcim/inc/device_import_header.html' %}
{% endblock %}

View File

@ -1,5 +0,0 @@
{% extends 'generic/bulk_import.html' %}
{% block tabs %}
{% include 'dcim/inc/device_import_header.html' with active_tab='child_import' %}
{% endblock %}

View File

@ -1,8 +0,0 @@
<ul class="nav nav-tabs px-3">
<li class="nav-item" role="presentation">
<a class ="nav-link{% if not active_tab %} active{% endif %}" href="{% url 'dcim:device_import' %}">Racked Devices</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link{% if active_tab == 'child_import' %} active{% endif %}" href="{% url 'dcim:device_import_child' %}">Child Devices</a>
</li>
</ul>