1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Move component bulk creation views to new URLs

This commit is contained in:
Jeremy Stretch
2020-02-05 12:36:38 -05:00
parent 6b9fa5e76f
commit 75906f7591
12 changed files with 111 additions and 97 deletions

View File

@ -2180,6 +2180,10 @@ class ConsolePortForm(BootstrapMixin, forms.ModelForm):
class ConsolePortCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -2238,6 +2242,10 @@ class ConsoleServerPortForm(BootstrapMixin, forms.ModelForm):
class ConsoleServerPortCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -2331,6 +2339,10 @@ class PowerPortForm(BootstrapMixin, forms.ModelForm):
class PowerPortCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -2412,6 +2424,10 @@ class PowerOutletForm(BootstrapMixin, forms.ModelForm):
class PowerOutletCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -2437,11 +2453,12 @@ class PowerOutletCreateForm(ComponentForm):
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit power_port choices to those on the parent device
self.fields['power_port'].queryset = PowerPort.objects.filter(device=self.parent)
# Limit power_port queryset to PowerPorts which belong to the parent Device
if 'device' in self.initial:
device = Device.objects.filter(pk=self.initial['device']).first()
self.fields['power_port'].queryset = PowerPort.objects.filter(device=device)
class PowerOutletCSVForm(forms.ModelForm):
@ -2631,7 +2648,8 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
widget=StaticSelect2(),
)
enabled = forms.BooleanField(
required=False
required=False,
initial=True
)
lag = forms.ModelChoiceField(
queryset=Interface.objects.all(),
@ -2686,21 +2704,15 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form):
)
def __init__(self, *args, **kwargs):
# Set interfaces enabled by default
kwargs['initial'] = kwargs.get('initial', {}).copy()
kwargs['initial'].update({'enabled': True})
super().__init__(*args, **kwargs)
# Limit LAG choices to interfaces belonging to this device (or its VC master)
if self.parent is not None:
# Limit LAG choices to interfaces which belong to the parent device (or VC master)
if 'device' in self.initial:
device = Device.objects.filter(pk=self.initial['device']).first()
self.fields['lag'].queryset = Interface.objects.filter(
device__in=[self.parent, self.parent.get_vc_master()],
device__in=[device, device.get_vc_master()],
type=InterfaceTypeChoices.TYPE_LAG
)
else:
self.fields['lag'].queryset = Interface.objects.none()
class InterfaceCSVForm(forms.ModelForm):
@ -2917,6 +2929,10 @@ class FrontPortForm(BootstrapMixin, forms.ModelForm):
# TODO: Merge with FrontPortTemplateCreateForm to remove duplicate logic
class FrontPortCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -2936,15 +2952,17 @@ class FrontPortCreateForm(ComponentForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
parent = Device.objects.get(pk=self.initial['device'])
# Determine which rear port positions are occupied. These will be excluded from the list of available mappings.
occupied_port_positions = [
(front_port.rear_port_id, front_port.rear_port_position)
for front_port in self.parent.frontports.all()
for front_port in parent.frontports.all()
]
# Populate rear port choices
choices = []
rear_ports = RearPort.objects.filter(device=self.parent)
rear_ports = RearPort.objects.filter(device=parent)
for rear_port in rear_ports:
for i in range(1, rear_port.positions + 1):
if (rear_port.pk, i) not in occupied_port_positions:
@ -3084,6 +3102,10 @@ class RearPortForm(BootstrapMixin, forms.ModelForm):
class RearPortCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -3688,6 +3710,10 @@ class DeviceBayForm(BootstrapMixin, forms.ModelForm):
class DeviceBayCreateForm(ComponentForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)

View File

@ -169,8 +169,8 @@ urlpatterns = [
# Console ports
path(r'devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
path(r'devices/<int:pk>/console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'),
path(r'console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'),
path(r'console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'),
path(r'console-ports/import/', views.ConsolePortBulkImportView.as_view(), name='consoleport_import'),
# TODO: Bulk edit view for ConsolePorts
path(r'console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
@ -181,10 +181,10 @@ urlpatterns = [
# Console server ports
path(r'devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
path(r'devices/<int:pk>/console-server-ports/add/', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'),
path(r'console-server-ports/', views.ConsoleServerPortListView.as_view(), name='consoleserverport_list'),
path(r'console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
path(r'console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
path(r'console-server-ports/add/', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'),
path(r'console-server-ports/import/', views.ConsoleServerPortBulkImportView.as_view(), name='consoleserverport_import'),
path(r'console-server-ports/edit/', views.ConsoleServerPortBulkEditView.as_view(), name='consoleserverport_bulk_edit'),
path(r'console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
@ -195,8 +195,8 @@ urlpatterns = [
# Power ports
path(r'devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
path(r'devices/<int:pk>/power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'),
path(r'power-ports/', views.PowerPortListView.as_view(), name='powerport_list'),
path(r'power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'),
path(r'power-ports/import/', views.PowerPortBulkImportView.as_view(), name='powerport_import'),
# TODO: Bulk edit view for PowerPorts
path(r'power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
@ -207,10 +207,10 @@ urlpatterns = [
# Power outlets
path(r'devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
path(r'devices/<int:pk>/power-outlets/add/', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'),
path(r'power-outlets/', views.PowerOutletListView.as_view(), name='poweroutlet_list'),
path(r'power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
path(r'power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
path(r'power-outlets/add/', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'),
path(r'power-outlets/import/', views.PowerOutletBulkImportView.as_view(), name='poweroutlet_import'),
path(r'power-outlets/edit/', views.PowerOutletBulkEditView.as_view(), name='poweroutlet_bulk_edit'),
path(r'power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
@ -221,10 +221,10 @@ urlpatterns = [
# Interfaces
path(r'devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
path(r'devices/<int:pk>/interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'),
path(r'interfaces/', views.InterfaceListView.as_view(), name='interface_list'),
path(r'interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
path(r'interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
path(r'interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'),
path(r'interfaces/import/', views.InterfaceBulkImportView.as_view(), name='interface_import'),
path(r'interfaces/edit/', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
path(r'interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
@ -237,10 +237,10 @@ urlpatterns = [
# Front ports
# path(r'devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
path(r'devices/<int:pk>/front-ports/add/', views.FrontPortCreateView.as_view(), name='frontport_add'),
path(r'front-ports/', views.FrontPortListView.as_view(), name='frontport_list'),
path(r'front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'),
path(r'front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
path(r'front-ports/add/', views.FrontPortCreateView.as_view(), name='frontport_add'),
path(r'front-ports/import/', views.FrontPortBulkImportView.as_view(), name='frontport_import'),
path(r'front-ports/edit/', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'),
path(r'front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
@ -251,10 +251,10 @@ urlpatterns = [
# Rear ports
# path(r'devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
path(r'devices/<int:pk>/rear-ports/add/', views.RearPortCreateView.as_view(), name='rearport_add'),
path(r'rear-ports/', views.RearPortListView.as_view(), name='rearport_list'),
path(r'rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'),
path(r'rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
path(r'rear-ports/add/', views.RearPortCreateView.as_view(), name='rearport_add'),
path(r'rear-ports/import/', views.RearPortBulkImportView.as_view(), name='rearport_import'),
path(r'rear-ports/edit/', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'),
path(r'rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
@ -265,9 +265,9 @@ urlpatterns = [
# Device bays
path(r'devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
path(r'devices/<int:pk>/bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'),
path(r'device-bays/', views.DeviceBayListView.as_view(), name='devicebay_list'),
path(r'device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
path(r'device-bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'),
path(r'device-bays/import/', views.DeviceBayBulkImportView.as_view(), name='devicebay_import'),
# TODO: Bulk edit view for DeviceBays
path(r'device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
@ -283,6 +283,7 @@ urlpatterns = [
path(r'inventory-items/delete/', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'),
path(r'inventory-items/<int:pk>/edit/', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
path(r'inventory-items/<int:pk>/delete/', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
# TODO: Replace below with InventoryItemCreateView
path(r'devices/<int:device>/inventory-items/add/', views.InventoryItemEditView.as_view(), name='inventoryitem_add'),
# Cables

View File

@ -1205,8 +1205,6 @@ class ConsolePortListView(PermissionRequiredMixin, ObjectListView):
class ConsolePortCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_consoleport'
parent_model = Device
parent_field = 'device'
model = ConsolePort
form = forms.ConsolePortCreateForm
model_form = forms.ConsolePortForm
@ -1253,8 +1251,6 @@ class ConsoleServerPortListView(PermissionRequiredMixin, ObjectListView):
class ConsoleServerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_consoleserverport'
parent_model = Device
parent_field = 'device'
model = ConsoleServerPort
form = forms.ConsoleServerPortCreateForm
model_form = forms.ConsoleServerPortForm
@ -1320,8 +1316,6 @@ class PowerPortListView(PermissionRequiredMixin, ObjectListView):
class PowerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_powerport'
parent_model = Device
parent_field = 'device'
model = PowerPort
form = forms.PowerPortCreateForm
model_form = forms.PowerPortForm
@ -1368,8 +1362,6 @@ class PowerOutletListView(PermissionRequiredMixin, ObjectListView):
class PowerOutletCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_poweroutlet'
parent_model = Device
parent_field = 'device'
model = PowerOutlet
form = forms.PowerOutletCreateForm
model_form = forms.PowerOutletForm
@ -1471,8 +1463,6 @@ class InterfaceView(PermissionRequiredMixin, View):
class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_interface'
parent_model = Device
parent_field = 'device'
model = Interface
form = forms.InterfaceCreateForm
model_form = forms.InterfaceForm
@ -1539,8 +1529,6 @@ class FrontPortListView(PermissionRequiredMixin, ObjectListView):
class FrontPortCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_frontport'
parent_model = Device
parent_field = 'device'
model = FrontPort
form = forms.FrontPortCreateForm
model_form = forms.FrontPortForm
@ -1606,8 +1594,6 @@ class RearPortListView(PermissionRequiredMixin, ObjectListView):
class RearPortCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_rearport'
parent_model = Device
parent_field = 'device'
model = RearPort
form = forms.RearPortCreateForm
model_form = forms.RearPortForm
@ -1675,8 +1661,6 @@ class DeviceBayListView(PermissionRequiredMixin, ObjectListView):
class DeviceBayCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_devicebay'
parent_model = Device
parent_field = 'device'
model = DeviceBay
form = forms.DeviceBayCreateForm
model_form = forms.DeviceBayForm

View File

@ -48,14 +48,30 @@
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Components <span class="caret"></span>
</button>
<ul class="dropdown-menu">
{% if perms.dcim.add_consoleport %}<li><a href="{% url 'dcim:consoleport_add' pk=device.pk %}">Console Ports</a></li>{% endif %}
{% if perms.dcim.add_consoleserverport %}<li><a href="{% url 'dcim:consoleserverport_add' pk=device.pk %}">Console Server Ports</a></li>{% endif %}
{% if perms.dcim.add_powerport %}<li><a href="{% url 'dcim:powerport_add' pk=device.pk %}">Power Ports</a></li>{% endif %}
{% if perms.dcim.add_poweroutlet %}<li><a href="{% url 'dcim:poweroutlet_add' pk=device.pk %}">Power Outlets</a></li>{% endif %}
{% if perms.dcim.add_interface %}<li><a href="{% url 'dcim:interface_add' pk=device.pk %}">Interfaces</a></li>{% endif %}
{% if perms.dcim.add_frontport %}<li><a href="{% url 'dcim:frontport_add' pk=device.pk %}">Front Ports</a></li>{% endif %}
{% if perms.dcim.add_rearport %}<li><a href="{% url 'dcim:rearport_add' pk=device.pk %}">Rear Ports</a></li>{% endif %}
{% if perms.dcim.add_devicebay %}<li><a href="{% url 'dcim:devicebay_add' pk=device.pk %}">Device Bays</a></li>{% endif %}
{% if perms.dcim.add_consoleport %}
<li><a href="{% url 'dcim:consoleport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Console Ports</a></li>
{% endif %}
{% if perms.dcim.add_consoleserverport %}
<li><a href="{% url 'dcim:consoleserverport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Console Server Ports</a></li>
{% endif %}
{% if perms.dcim.add_powerport %}
<li><a href="{% url 'dcim:powerport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Power Ports</a></li>
{% endif %}
{% if perms.dcim.add_poweroutlet %}
<li><a href="{% url 'dcim:poweroutlet_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Power Outlets</a></li>
{% endif %}
{% if perms.dcim.add_interface %}
<li><a href="{% url 'dcim:interface_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Interfaces</a></li>
{% endif %}
{% if perms.dcim.add_frontport %}
<li><a href="{% url 'dcim:frontport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Front Ports</a></li>
{% endif %}
{% if perms.dcim.add_rearport %}
<li><a href="{% url 'dcim:rearport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Rear Ports</a></li>
{% endif %}
{% if perms.dcim.add_devicebay %}
<li><a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Device Bays</a></li>
{% endif %}
</ul>
</div>
{% endif %}
@ -333,12 +349,12 @@
{% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}
<div class="panel-footer text-right noprint">
{% if perms.dcim.add_consoleport %}
<a href="{% url 'dcim:consoleport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
<a href="{% url 'dcim:consoleport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console port
</a>
{% endif %}
{% if perms.dcim.add_powerport %}
<a href="{% url 'dcim:powerport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
<a href="{% url 'dcim:powerport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power port
</a>
{% endif %}
@ -530,7 +546,7 @@
{% endif %}
{% if perms.dcim.add_devicebay %}
<div class="pull-right">
<a href="{% url 'dcim:devicebay_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add device bays
</a>
</div>
@ -603,7 +619,7 @@
{% endif %}
{% if perms.dcim.add_interface %}
<div class="pull-right">
<a href="{% url 'dcim:interface_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:interface_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add interfaces
</a>
</div>
@ -664,7 +680,7 @@
{% endif %}
{% if perms.dcim.add_consoleserverport %}
<div class="pull-right">
<a href="{% url 'dcim:consoleserverport_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:consoleserverport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console server ports
</a>
</div>
@ -726,7 +742,7 @@
{% endif %}
{% if perms.dcim.add_poweroutlet %}
<div class="pull-right">
<a href="{% url 'dcim:poweroutlet_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:poweroutlet_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power outlets
</a>
</div>
@ -787,7 +803,7 @@
{% endif %}
{% if perms.dcim.add_frontport %}
<div class="pull-right">
<a href="{% url 'dcim:frontport_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:frontport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add front ports
</a>
</div>
@ -845,7 +861,7 @@
{% endif %}
{% if perms.dcim.add_rearport %}
<div class="pull-right">
<a href="{% url 'dcim:rearport_add' pk=device.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'dcim:rearport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add rear ports
</a>
</div>

View File

@ -1,14 +1,11 @@
{% extends '_base.html' %}
{% load form_helpers %}
{% block title %}Create {{ component_type }} ({{ parent }}){% endblock %}
{% block title %}Create {{ component_type }}{% endblock %}
{% block content %}
<form action="." method="post" class="form form-horizontal">
<form action="" method="post" class="form form-horizontal">
{% csrf_token %}
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<div class="row">
<div class="col-md-6 col-md-offset-3">
{% if form.non_field_errors %}
@ -27,7 +24,7 @@
<div class="form-group">
<label class="col-md-3 control-label required">Device</label>
<div class="col-md-9">
<p class="form-control-static">{{ parent }}</p>
<p class="form-control-static">{{ form.device.value }}</p>
</div>
</div>
{% render_form form %}

View File

@ -299,7 +299,7 @@
{% endif %}
{% if perms.dcim.add_interface %}
<div class="pull-right">
<a href="{% url 'virtualization:interface_add' pk=virtualmachine.pk %}" class="btn btn-primary btn-xs">
<a href="{% url 'virtualization:interface_add' %}?virtual_machine={{ virtualmachine.pk }}&return_url={{ virtualmachine.get_absolute_url }}" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add interfaces
</a>
</div>

View File

@ -5,7 +5,7 @@
{% block title %}Create {{ component_type }} ({{ parent }}){% endblock %}
{% block content %}
<form action="." method="post" class="form form-horizontal">
<form action="" method="post" class="form form-horizontal">
{% csrf_token %}
<div class="row">
<div class="col-md-6 col-md-offset-3">

View File

@ -727,14 +727,11 @@ class ConfirmationForm(BootstrapMixin, ReturnURLForm):
confirm = forms.BooleanField(required=True, widget=forms.HiddenInput(), initial=True)
# TODO: Remove ComponentForm
class ComponentForm(BootstrapMixin, forms.Form):
"""
Allow inclusion of the parent Device/VirtualMachine as context for limiting field choices.
"""
def __init__(self, parent, *args, **kwargs):
self.parent = parent
super().__init__(*args, **kwargs)
def get_iterative_data(self, iteration):
return {}

View File

@ -820,7 +820,8 @@ class BulkDeleteView(GetReturnURLMixin, View):
# Device/VirtualMachine components
#
class ComponentCreateView(View):
# TODO: Replace with BulkCreateView
class ComponentCreateView(GetReturnURLMixin, View):
"""
Add one or more components (e.g. interfaces, console ports, etc.) to a Device or VirtualMachine.
"""
@ -831,30 +832,23 @@ class ComponentCreateView(View):
model_form = None
template_name = None
def get(self, request, pk):
def get(self, request):
parent = get_object_or_404(self.parent_model, pk=pk)
data = deepcopy(request.GET)
data[self.parent_field] = parent.pk
form = self.form(parent, initial=data)
form = self.form(initial=request.GET)
return render(request, self.template_name, {
'parent': parent,
'component_type': self.model._meta.verbose_name,
'form': form,
'return_url': parent.get_absolute_url(),
'return_url': self.get_return_url(request),
})
def post(self, request, pk):
def post(self, request):
parent = get_object_or_404(self.parent_model, pk=pk)
form = self.form(parent, request.POST)
form = self.form(request.POST, initial=request.GET)
if form.is_valid():
new_components = []
data = deepcopy(request.POST)
data[self.parent_field] = parent.pk
for i, name in enumerate(form.cleaned_data['name_pattern']):
@ -879,19 +873,18 @@ class ComponentCreateView(View):
for component_form in new_components:
component_form.save()
messages.success(request, "Added {} {} to {}.".format(
len(new_components), self.model._meta.verbose_name_plural, parent
messages.success(request, "Added {} {}".format(
len(new_components), self.model._meta.verbose_name_plural
))
if '_addanother' in request.POST:
return redirect(request.path)
return redirect(request.get_full_path())
else:
return redirect(parent.get_absolute_url())
return redirect(self.get_return_url(request))
return render(request, self.template_name, {
'parent': parent,
'component_type': self.model._meta.verbose_name,
'form': form,
'return_url': parent.get_absolute_url(),
'return_url': self.get_return_url(request),
})

View File

@ -739,6 +739,10 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
class InterfaceCreateForm(ComponentForm):
virtual_machine = forms.ModelChoiceField(
queryset=VirtualMachine.objects.all(),
widget=forms.HiddenInput()
)
name_pattern = ExpandableNameField(
label='Name'
)
@ -748,7 +752,8 @@ class InterfaceCreateForm(ComponentForm):
widget=forms.HiddenInput()
)
enabled = forms.BooleanField(
required=False
required=False,
initial=True
)
mtu = forms.IntegerField(
required=False,
@ -793,13 +798,9 @@ class InterfaceCreateForm(ComponentForm):
def __init__(self, *args, **kwargs):
# Set interfaces enabled by default
kwargs['initial'] = kwargs.get('initial', {}).copy()
kwargs['initial'].update({'enabled': True})
super().__init__(*args, **kwargs)
# Limit VLan choices to those in: global vlans, global groups, the current site's group, the current site
# Limit VLAN choices to those in: global vlans, global groups, the current site's group, the current site
vlan_choices = []
global_vlans = VLAN.objects.filter(site=None, group=None)
vlan_choices.append(
@ -811,7 +812,8 @@ class InterfaceCreateForm(ComponentForm):
(group.name, [(vlan.pk, vlan) for vlan in global_group_vlans])
)
site = getattr(self.parent.cluster, 'site', None)
parent = VirtualMachine.objects.get(pk=self.initial['virtual_machine'])
site = getattr(parent.cluster, 'site', None)
if site is not None:
# Add non-grouped site VLANs

View File

@ -52,7 +52,7 @@ urlpatterns = [
# VM interfaces
path(r'virtual-machines/interfaces/add/', views.VirtualMachineBulkAddInterfaceView.as_view(), name='virtualmachine_bulk_add_interface'),
path(r'virtual-machines/<int:pk>/interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'),
path(r'interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'),
path(r'interfaces/edit/', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
path(r'interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
# TODO: Rename vm-interfaces to interfaces

View File

@ -330,8 +330,6 @@ class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
permission_required = 'dcim.add_interface'
parent_model = VirtualMachine
parent_field = 'virtual_machine'
model = Interface
form = forms.InterfaceCreateForm
model_form = forms.InterfaceForm