mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 04:02:52 -06:00
Fixes #11528: Permit import of devices using uploaded file
This commit is contained in:
parent
d5ccda355f
commit
b8de9c0875
@ -18,7 +18,6 @@ from .common import ModuleCommonForm
|
|||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'CableImportForm',
|
'CableImportForm',
|
||||||
'ChildDeviceImportForm',
|
|
||||||
'ConsolePortImportForm',
|
'ConsolePortImportForm',
|
||||||
'ConsoleServerPortImportForm',
|
'ConsoleServerPortImportForm',
|
||||||
'DeviceBayImportForm',
|
'DeviceBayImportForm',
|
||||||
@ -413,6 +412,18 @@ class DeviceImportForm(BaseDeviceImportForm):
|
|||||||
required=False,
|
required=False,
|
||||||
help_text=_('Mounted rack face')
|
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(
|
airflow = CSVChoiceField(
|
||||||
choices=DeviceAirflowChoices,
|
choices=DeviceAirflowChoices,
|
||||||
required=False,
|
required=False,
|
||||||
@ -422,8 +433,8 @@ class DeviceImportForm(BaseDeviceImportForm):
|
|||||||
class Meta(BaseDeviceImportForm.Meta):
|
class Meta(BaseDeviceImportForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'site', 'location', 'rack', 'position', 'face', 'airflow', 'virtual_chassis', 'vc_position', 'vc_priority',
|
'site', 'location', 'rack', 'position', 'face', 'parent', 'device_bay', 'airflow', 'virtual_chassis',
|
||||||
'cluster', 'description', 'comments', 'tags',
|
'vc_position', 'vc_priority', 'cluster', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -434,6 +445,7 @@ class DeviceImportForm(BaseDeviceImportForm):
|
|||||||
# Limit location queryset by assigned site
|
# Limit location queryset by assigned site
|
||||||
params = {f"site__{self.fields['site'].to_field_name}": data.get('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['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
|
# Limit rack queryset by assigned site and group
|
||||||
params = {
|
params = {
|
||||||
@ -442,6 +454,23 @@ class DeviceImportForm(BaseDeviceImportForm):
|
|||||||
}
|
}
|
||||||
self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
|
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):
|
class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm):
|
||||||
device = CSVModelChoiceField(
|
device = CSVModelChoiceField(
|
||||||
@ -495,48 +524,6 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm):
|
|||||||
return self.cleaned_data['replicate_components']
|
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
|
# Device components
|
||||||
#
|
#
|
||||||
|
@ -177,7 +177,6 @@ urlpatterns = [
|
|||||||
path('devices/', views.DeviceListView.as_view(), name='device_list'),
|
path('devices/', views.DeviceListView.as_view(), name='device_list'),
|
||||||
path('devices/add/', views.DeviceEditView.as_view(), name='device_add'),
|
path('devices/add/', views.DeviceEditView.as_view(), name='device_add'),
|
||||||
path('devices/import/', views.DeviceBulkImportView.as_view(), name='device_import'),
|
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/edit/', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
|
||||||
path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'),
|
path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'),
|
||||||
path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'),
|
path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'),
|
||||||
|
@ -2090,19 +2090,12 @@ class DeviceBulkImportView(generic.BulkImportView):
|
|||||||
queryset = Device.objects.all()
|
queryset = Device.objects.all()
|
||||||
model_form = forms.DeviceImportForm
|
model_form = forms.DeviceImportForm
|
||||||
table = tables.DeviceImportTable
|
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):
|
def save_object(self, object_form, request):
|
||||||
obj = object_form.save()
|
obj = object_form.save()
|
||||||
|
|
||||||
# Save the reverse relation to the parent device bay
|
# 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 = obj.parent_bay
|
||||||
device_bay.installed_device = obj
|
device_bay.installed_device = obj
|
||||||
device_bay.save()
|
device_bay.save()
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
{% extends 'generic/bulk_import.html' %}
|
|
||||||
|
|
||||||
{% block tabs %}
|
|
||||||
{% include 'dcim/inc/device_import_header.html' %}
|
|
||||||
{% endblock %}
|
|
@ -1,5 +0,0 @@
|
|||||||
{% extends 'generic/bulk_import.html' %}
|
|
||||||
|
|
||||||
{% block tabs %}
|
|
||||||
{% include 'dcim/inc/device_import_header.html' with active_tab='child_import' %}
|
|
||||||
{% endblock %}
|
|
@ -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>
|
|
Loading…
Reference in New Issue
Block a user