Closes #1781: Enable bulk renaming of device components

This commit is contained in:
Jeremy Stretch
2018-01-10 15:48:07 -05:00
parent 9c27d18d6c
commit fc7a43f23e
6 changed files with 250 additions and 89 deletions

View File

@@ -50,6 +50,14 @@ def get_device_by_name_or_pk(name):
return device
class BulkRenameForm(forms.Form):
"""
An extendable form to be used for renaming device components in bulk.
"""
find = forms.CharField()
replace = forms.CharField()
#
# Regions
#
@@ -1346,6 +1354,10 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.
}
class ConsoleServerPortBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(queryset=ConsoleServerPort.objects.all(), widget=forms.MultipleHiddenInput)
class ConsoleServerPortBulkDisconnectForm(ConfirmationForm):
pk = forms.ModelMultipleChoiceField(queryset=ConsoleServerPort.objects.all(), widget=forms.MultipleHiddenInput)
@@ -1607,6 +1619,10 @@ class PowerOutletConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
}
class PowerOutletBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(queryset=PowerOutlet.objects.all(), widget=forms.MultipleHiddenInput)
class PowerOutletBulkDisconnectForm(ConfirmationForm):
pk = forms.ModelMultipleChoiceField(queryset=PowerOutlet.objects.all(), widget=forms.MultipleHiddenInput)
@@ -1936,6 +1952,10 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm, ChainedFieldsMixin):
self.fields['tagged_vlans'].queryset = VLAN.objects.filter(**filter_dict)
class InterfaceBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(queryset=Interface.objects.all(), widget=forms.MultipleHiddenInput)
class InterfaceBulkDisconnectForm(ConfirmationForm):
pk = forms.ModelMultipleChoiceField(queryset=Interface.objects.all(), widget=forms.MultipleHiddenInput)
@@ -2143,6 +2163,10 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
).exclude(pk=device_bay.device.pk)
class DeviceBayBulkRenameForm(BulkRenameForm):
pk = forms.ModelMultipleChoiceField(queryset=DeviceBay.objects.all(), widget=forms.MultipleHiddenInput)
#
# Connections
#

View File

@@ -154,6 +154,7 @@ urlpatterns = [
url(r'^console-server-ports/(?P<pk>\d+)/disconnect/$', views.ConsoleServerPortDisconnectView.as_view(), name='consoleserverport_disconnect'),
url(r'^console-server-ports/(?P<pk>\d+)/edit/$', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'),
url(r'^console-server-ports/(?P<pk>\d+)/delete/$', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'),
url(r'^console-server-ports/rename/$', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
# Power ports
url(r'^devices/power-ports/add/$', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
@@ -173,6 +174,7 @@ urlpatterns = [
url(r'^power-outlets/(?P<pk>\d+)/disconnect/$', views.PowerOutletDisconnectView.as_view(), name='poweroutlet_disconnect'),
url(r'^power-outlets/(?P<pk>\d+)/edit/$', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'),
url(r'^power-outlets/(?P<pk>\d+)/delete/$', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'),
url(r'^power-outlets/rename/$', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
# Interfaces
url(r'^devices/interfaces/add/$', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
@@ -184,6 +186,7 @@ urlpatterns = [
url(r'^interface-connections/(?P<pk>\d+)/delete/$', views.InterfaceConnectionDeleteView.as_view(), name='interfaceconnection_delete'),
url(r'^interfaces/(?P<pk>\d+)/edit/$', views.InterfaceEditView.as_view(), name='interface_edit'),
url(r'^interfaces/(?P<pk>\d+)/delete/$', views.InterfaceDeleteView.as_view(), name='interface_delete'),
url(r'^interfaces/rename/$', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
# Device bays
url(r'^devices/device-bays/add/$', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
@@ -193,6 +196,7 @@ urlpatterns = [
url(r'^device-bays/(?P<pk>\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
url(r'^device-bays/(?P<pk>\d+)/populate/$', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'),
url(r'^device-bays/(?P<pk>\d+)/depopulate/$', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'),
url(r'^device-bays/rename/$', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
# Inventory items
url(r'^devices/(?P<device>\d+)/inventory-items/add/$', views.InventoryItemEditView.as_view(), name='inventoryitem_add'),

View File

@@ -12,7 +12,7 @@ from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.html import escape
from django.utils.http import urlencode
from django.utils.http import is_safe_url, urlencode
from django.utils.safestring import mark_safe
from django.views.generic import View
from natsort import natsorted
@@ -37,6 +37,50 @@ from .models import (
)
class BulkRenameView(View):
"""
An extendable view for renaming device components in bulk.
"""
model = None
form = None
template_name = 'dcim/bulk_rename.html'
def post(self, request):
return_url = request.GET.get('return_url')
if not return_url or not is_safe_url(url=return_url, host=request.get_host()):
return_url = 'home'
if '_preview' in request.POST or '_apply' in request.POST:
form = self.form(request.POST, initial={'pk': request.POST.getlist('pk')})
selected_objects = self.model.objects.filter(pk__in=form.initial['pk'])
if form.is_valid():
for obj in selected_objects:
obj.new_name = obj.name.replace(form.cleaned_data['find'], form.cleaned_data['replace'])
if '_apply' in request.POST:
for obj in selected_objects:
obj.name = obj.new_name
obj.save()
messages.success(request, "Renamed {} {}".format(
len(selected_objects),
self.model._meta.verbose_name_plural
))
return redirect(return_url)
else:
form = self.form(initial={'pk': request.POST.getlist('pk')})
selected_objects = self.model.objects.filter(pk__in=form.initial['pk'])
return render(request, self.template_name, {
'form': form,
'obj_type_plural': self.model._meta.verbose_name_plural,
'selected_objects': selected_objects,
'return_url': return_url,
})
class BulkDisconnectView(View):
"""
An extendable view for disconnection console/power/interface components in bulk.
@@ -1270,6 +1314,12 @@ class ConsoleServerPortDeleteView(PermissionRequiredMixin, ObjectDeleteView):
model = ConsoleServerPort
class ConsoleServerPortBulkRenameView(PermissionRequiredMixin, BulkRenameView):
permission_required = 'dcim.change_consoleserverport'
model = ConsoleServerPort
form = forms.ConsoleServerPortBulkRenameForm
class ConsoleServerPortBulkDisconnectView(PermissionRequiredMixin, BulkDisconnectView):
permission_required = 'dcim.change_consoleserverport'
model = ConsoleServerPort
@@ -1548,6 +1598,12 @@ class PowerOutletDeleteView(PermissionRequiredMixin, ObjectDeleteView):
model = PowerOutlet
class PowerOutletBulkRenameView(PermissionRequiredMixin, BulkRenameView):
permission_required = 'dcim.change_poweroutlet'
model = PowerOutlet
form = forms.PowerOutletBulkRenameForm
class PowerOutletBulkDisconnectView(PermissionRequiredMixin, BulkDisconnectView):
permission_required = 'dcim.change_poweroutlet'
model = PowerOutlet
@@ -1612,6 +1668,12 @@ class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
form = forms.InterfaceBulkEditForm
class InterfaceBulkRenameView(PermissionRequiredMixin, BulkRenameView):
permission_required = 'dcim.change_interface'
model = Interface
form = forms.InterfaceBulkRenameForm
class InterfaceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_interface'
cls = Interface
@@ -1713,6 +1775,12 @@ class DeviceBayDepopulateView(PermissionRequiredMixin, View):
})
class DeviceBayBulkRenameView(PermissionRequiredMixin, BulkRenameView):
permission_required = 'dcim.change_devicebay'
model = DeviceBay
form = forms.DeviceBayBulkRenameForm
class DeviceBayBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_devicebay'
cls = DeviceBay