netbox/netbox/ipam/views.py
2016-03-04 11:25:20 -05:00

800 lines
26 KiB
Python

from netaddr import IPSet
from django_tables2 import RequestConfig
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.urlresolvers import reverse
from django.db.models import ProtectedError
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.http import urlencode
from dcim.models import Device
from utilities.error_handlers import handle_protectederror
from utilities.forms import ConfirmationForm
from utilities.paginator import EnhancedPaginator
from utilities.views import BulkImportView, BulkEditView, BulkDeleteView, ObjectListView
from .filters import AggregateFilter, PrefixFilter, IPAddressFilter, VLANFilter, VRFFilter
from .forms import AggregateForm, AggregateImportForm, AggregateBulkEditForm, AggregateBulkDeleteForm, \
AggregateFilterForm, PrefixForm, PrefixImportForm, PrefixBulkEditForm, PrefixBulkDeleteForm, PrefixFilterForm, \
IPAddressForm, IPAddressImportForm, IPAddressBulkEditForm, IPAddressBulkDeleteForm, IPAddressFilterForm, VLANForm, \
VLANImportForm, VLANBulkEditForm, VLANBulkDeleteForm, VRFForm, VRFImportForm, VRFBulkEditForm, VRFBulkDeleteForm, \
VLANFilterForm
from .models import VRF, Aggregate, Prefix, VLAN
from .tables import AggregateTable, AggregateBulkEditTable, PrefixTable, PrefixBriefTable, PrefixBulkEditTable, \
IPAddress, IPAddressBriefTable, IPAddressTable, IPAddressBulkEditTable, VLANTable, VLANBulkEditTable, VRFTable, \
VRFBulkEditTable
def add_available_prefixes(parent, prefix_list):
"""
Create fake Prefix objects for all unallocated space within a prefix.
"""
# Find all unallocated space
available_prefixes = IPSet(parent) ^ IPSet([p.prefix for p in prefix_list])
available_prefixes = [Prefix(prefix=p) for p in available_prefixes.iter_cidrs()]
# Concatenate and sort complete list of children
prefix_list = list(prefix_list) + available_prefixes
prefix_list.sort(key=lambda p: p.prefix)
return prefix_list
#
# VRFs
#
class VRFListView(ObjectListView):
queryset = VRF.objects.all()
filter = VRFFilter
table = VRFTable
edit_table = VRFBulkEditTable
edit_table_permissions = ['ipam.change_vrf', 'ipam.delete_vrf']
template_name = 'ipam/vrf_list.html'
def vrf(request, pk):
vrf = get_object_or_404(VRF.objects.all(), pk=pk)
prefixes = Prefix.objects.filter(vrf=vrf)
return render(request, 'ipam/vrf.html', {
'vrf': vrf,
'prefixes': prefixes,
})
@permission_required('ipam.add_vrf')
def vrf_add(request):
if request.method == 'POST':
form = VRFForm(request.POST)
if form.is_valid():
vrf = form.save()
messages.success(request, "Added new VRF: {0}".format(vrf))
if '_addanother' in request.POST:
return redirect('ipam:vrf_add')
else:
return redirect('ipam:vrf', pk=vrf.pk)
else:
form = VRFForm()
return render(request, 'ipam/vrf_edit.html', {
'form': form,
'cancel_url': reverse('ipam:vrf_list'),
})
@permission_required('ipam.change_vrf')
def vrf_edit(request, pk):
vrf = get_object_or_404(VRF, pk=pk)
if request.method == 'POST':
form = VRFForm(request.POST, instance=vrf)
if form.is_valid():
vrf = form.save()
messages.success(request, "Modified VRF {0}".format(vrf))
return redirect('ipam:vrf', pk=vrf.pk)
else:
form = VRFForm(instance=vrf)
return render(request, 'ipam/vrf_edit.html', {
'vrf': vrf,
'form': form,
'cancel_url': reverse('ipam:vrf', kwargs={'pk': vrf.pk}),
})
@permission_required('ipam.delete_vrf')
def vrf_delete(request, pk):
vrf = get_object_or_404(VRF, pk=pk)
if request.method == 'POST':
form = ConfirmationForm(request.POST)
if form.is_valid():
try:
vrf.delete()
messages.success(request, "VRF {0} has been deleted".format(vrf))
return redirect('ipam:vrf_list')
except ProtectedError, e:
handle_protectederror(vrf, request, e)
return redirect('ipam:vrf', pk=vrf.pk)
else:
form = ConfirmationForm()
return render(request, 'ipam/vrf_delete.html', {
'vrf': vrf,
'form': form,
'cancel_url': reverse('ipam:vrf', kwargs={'pk': vrf.pk})
})
class VRFBulkImportView(PermissionRequiredMixin, BulkImportView):
permission_required = 'ipam.add_vrf'
form = VRFImportForm
table = VRFTable
template_name = 'ipam/vrf_import.html'
obj_list_url = 'ipam:vrf_list'
class VRFBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_vrf'
cls = VRF
form = VRFBulkEditForm
template_name = 'ipam/vrf_bulk_edit.html'
redirect_url = 'ipam:vrf_list'
def update_objects(self, pk_list, form):
fields_to_update = {}
for field in ['description']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
messages.success(self.request, "Updated {} VRFs".format(updated_count))
class VRFBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_vrf'
cls = VRF
form = VRFBulkDeleteForm
template_name = 'ipam/vrf_bulk_delete.html'
redirect_url = 'ipam:vrf_list'
#
# Aggregates
#
class AggregateListView(ObjectListView):
queryset = Aggregate.objects.select_related('rir').extra(select={
'child_count': 'SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix',
})
filter = AggregateFilter
filter_form = AggregateFilterForm
table = AggregateTable
edit_table = AggregateBulkEditTable
edit_table_permissions = ['ipam.change_aggregate', 'ipam.delete_aggregate']
template_name = 'ipam/aggregate_list.html'
def aggregate(request, pk):
aggregate = get_object_or_404(Aggregate, pk=pk)
# Find all child prefixes contained by this aggregate
child_prefixes = Prefix.objects.filter(prefix__net_contained_or_equal=str(aggregate.prefix))\
.select_related('site', 'status', 'role').annotate_depth(limit=0)
child_prefixes = add_available_prefixes(aggregate.prefix, child_prefixes)
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
prefix_table = PrefixBulkEditTable(child_prefixes)
else:
prefix_table = PrefixTable(child_prefixes)
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator})\
.configure(prefix_table)
return render(request, 'ipam/aggregate.html', {
'aggregate': aggregate,
'prefix_table': prefix_table,
})
@permission_required('ipam.add_aggregate')
def aggregate_add(request):
if request.method == 'POST':
form = AggregateForm(request.POST)
if form.is_valid():
aggregate = form.save()
messages.success(request, "Added new aggregate: {0}".format(aggregate.prefix))
if '_addanother' in request.POST:
return redirect('ipam:aggregate_add')
else:
return redirect('ipam:aggregate', pk=aggregate.pk)
else:
form = AggregateForm()
return render(request, 'ipam/aggregate_edit.html', {
'form': form,
'cancel_url': reverse('ipam:aggregate_list'),
})
@permission_required('ipam.change_aggregate')
def aggregate_edit(request, pk):
aggregate = get_object_or_404(Aggregate, pk=pk)
if request.method == 'POST':
form = AggregateForm(request.POST, instance=aggregate)
if form.is_valid():
aggregate = form.save()
messages.success(request, "Modified aggregate {0}".format(aggregate.prefix))
return redirect('ipam:aggregate', pk=aggregate.pk)
else:
form = AggregateForm(instance=aggregate)
return render(request, 'ipam/aggregate_edit.html', {
'aggregate': aggregate,
'form': form,
'cancel_url': reverse('ipam:aggregate', kwargs={'pk': aggregate.pk}),
})
@permission_required('ipam.delete_aggregate')
def aggregate_delete(request, pk):
aggregate = get_object_or_404(Aggregate, pk=pk)
if request.method == 'POST':
form = ConfirmationForm(request.POST)
if form.is_valid():
try:
aggregate.delete()
messages.success(request, "Aggregate {0} has been deleted".format(aggregate))
return redirect('ipam:aggregate_list')
except ProtectedError, e:
handle_protectederror(aggregate, request, e)
return redirect('ipam:aggregate', pk=aggregate.pk)
else:
form = ConfirmationForm()
return render(request, 'ipam/aggregate_delete.html', {
'aggregate': aggregate,
'form': form,
'cancel_url': reverse('ipam:aggregate', kwargs={'pk': aggregate.pk})
})
class AggregateBulkImportView(PermissionRequiredMixin, BulkImportView):
permission_required = 'ipam.add_aggregate'
form = AggregateImportForm
table = AggregateTable
template_name = 'ipam/aggregate_import.html'
obj_list_url = 'ipam:aggregate_list'
class AggregateBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_aggregate'
cls = Aggregate
form = AggregateBulkEditForm
template_name = 'ipam/aggregate_bulk_edit.html'
redirect_url = 'ipam:aggregate_list'
def update_objects(self, pk_list, form):
fields_to_update = {}
for field in ['rir', 'date_added', 'description']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
messages.success(self.request, "Updated {} aggregates".format(updated_count))
class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_aggregate'
cls = Aggregate
form = AggregateBulkDeleteForm
template_name = 'ipam/aggregate_bulk_delete.html'
redirect_url = 'ipam:aggregate_list'
#
# Prefixes
#
class PrefixListView(ObjectListView):
queryset = Prefix.objects.select_related('site', 'status', 'role')
filter = PrefixFilter
filter_form = PrefixFilterForm
table = PrefixTable
edit_table = PrefixBulkEditTable
edit_table_permissions = ['ipam.change_prefix', 'ipam.delete_prefix']
template_name = 'ipam/prefix_list.html'
def prefix(request, pk):
prefix = get_object_or_404(Prefix.objects.select_related('site', 'vlan', 'status', 'role'), pk=pk)
try:
aggregate = Aggregate.objects.get(prefix__net_contains_or_equals=str(prefix.prefix))
except Aggregate.DoesNotExist:
aggregate = None
# Count child IP addresses
ipaddress_count = IPAddress.objects.filter(address__net_contained_or_equal=str(prefix.prefix)).count()
# Parent prefixes table
parent_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix__net_contains=str(prefix.prefix))\
.select_related('site', 'status', 'role').annotate_depth()
parent_prefix_table = PrefixBriefTable(parent_prefixes)
# Duplicate prefixes table
duplicate_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix=str(prefix.prefix)).exclude(pk=prefix.pk)\
.select_related('site', 'status', 'role')
duplicate_prefix_table = PrefixBriefTable(duplicate_prefixes)
# Child prefixes table
child_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix))\
.select_related('site', 'status', 'role').annotate_depth(limit=0)
if child_prefixes:
child_prefixes = add_available_prefixes(prefix.prefix, child_prefixes)
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
child_prefix_table = PrefixBulkEditTable(child_prefixes)
else:
child_prefix_table = PrefixTable(child_prefixes)
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator})\
.configure(child_prefix_table)
return render(request, 'ipam/prefix.html', {
'prefix': prefix,
'aggregate': aggregate,
'ipaddress_count': ipaddress_count,
'parent_prefix_table': parent_prefix_table,
'child_prefix_table': child_prefix_table,
'duplicate_prefix_table': duplicate_prefix_table,
})
@permission_required('ipam.add_prefix')
def prefix_add(request):
if request.method == 'POST':
form = PrefixForm(request.POST)
if form.is_valid():
prefix = form.save()
messages.success(request, "Added new prefix: {0}".format(prefix.prefix))
if '_addanother' in request.POST:
return redirect('ipam:prefix_add')
else:
return redirect('ipam:prefix', pk=prefix.pk)
else:
form = PrefixForm(initial={
'site': request.GET.get('site'),
'vrf': request.GET.get('vrf'),
'prefix': request.GET.get('prefix'),
})
return render(request, 'ipam/prefix_edit.html', {
'form': form,
'cancel_url': reverse('ipam:prefix_list'),
})
@permission_required('ipam.change_prefix')
def prefix_edit(request, pk):
prefix = get_object_or_404(Prefix, pk=pk)
if request.method == 'POST':
form = PrefixForm(request.POST, instance=prefix)
if form.is_valid():
prefix = form.save()
messages.success(request, "Modified prefix {0}".format(prefix.prefix))
return redirect('ipam:prefix', pk=prefix.pk)
else:
form = PrefixForm(instance=prefix)
return render(request, 'ipam/prefix_edit.html', {
'prefix': prefix,
'form': form,
'cancel_url': reverse('ipam:prefix', kwargs={'pk': prefix.pk}),
})
@permission_required('ipam.delete_prefix')
def prefix_delete(request, pk):
prefix = get_object_or_404(Prefix, pk=pk)
if request.method == 'POST':
form = ConfirmationForm(request.POST)
if form.is_valid():
try:
prefix.delete()
messages.success(request, "Prefix {0} has been deleted".format(prefix))
return redirect('ipam:prefix_list')
except ProtectedError, e:
handle_protectederror(prefix, request, e)
return redirect('ipam:prefix', pk=prefix.pk)
else:
form = ConfirmationForm()
return render(request, 'ipam/prefix_delete.html', {
'prefix': prefix,
'form': form,
'cancel_url': reverse('ipam:prefix', kwargs={'pk': prefix.pk})
})
class PrefixBulkImportView(PermissionRequiredMixin, BulkImportView):
permission_required = 'ipam.add_prefix'
form = PrefixImportForm
table = PrefixTable
template_name = 'ipam/prefix_import.html'
obj_list_url = 'ipam:prefix_list'
class PrefixBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_prefix'
cls = Prefix
form = PrefixBulkEditForm
template_name = 'ipam/prefix_bulk_edit.html'
redirect_url = 'ipam:prefix_list'
def update_objects(self, pk_list, form):
fields_to_update = {}
if form.cleaned_data['vrf']:
fields_to_update['vrf'] = form.cleaned_data['vrf']
elif form.cleaned_data['vrf_global']:
fields_to_update['vrf'] = None
for field in ['site', 'status', 'role', 'description']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
messages.success(self.request, "Updated {} prefixes".format(updated_count))
class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_prefix'
cls = Prefix
form = PrefixBulkDeleteForm
template_name = 'ipam/prefix_bulk_delete.html'
redirect_url = 'ipam:prefix_list'
def prefix_ipaddresses(request, pk):
prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
# Find all IPAddresses belonging to this Prefix
ipaddresses = IPAddress.objects.filter(address__net_contained_or_equal=str(prefix.prefix))\
.select_related('vrf', 'interface__device', 'primary_for')
if request.user.has_perm('ipam.change_ipaddress') or request.user.has_perm('ipam.delete_ipaddress'):
ip_table = IPAddressBulkEditTable(ipaddresses)
else:
ip_table = IPAddressTable(ipaddresses)
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator})\
.configure(ip_table)
return render(request, 'ipam/prefix_ipaddresses.html', {
'prefix': prefix,
'ip_table': ip_table,
})
#
# IP addresses
#
class IPAddressListView(ObjectListView):
queryset = IPAddress.objects.select_related('vrf', 'interface__device', 'primary_for')
filter = IPAddressFilter
filter_form = IPAddressFilterForm
table = IPAddressTable
edit_table = IPAddressBulkEditTable
edit_table_permissions = ['ipam.change_ipaddress', 'ipam.delete_ipaddress']
template_name = 'ipam/ipaddress_list.html'
def ipaddress(request, pk):
ipaddress = get_object_or_404(IPAddress.objects.select_related('interface__device'), pk=pk)
parent_prefixes = Prefix.objects.filter(vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip))
related_ips = IPAddress.objects.select_related('interface__device').exclude(pk=ipaddress.pk).filter(vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address))
related_ips_table = IPAddressBriefTable(related_ips)
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator}).configure(related_ips_table)
return render(request, 'ipam/ipaddress.html', {
'ipaddress': ipaddress,
'parent_prefixes': parent_prefixes,
'related_ips_table': related_ips_table,
})
@permission_required('ipam.add_ipaddress')
def ipaddress_add(request):
if request.method == 'POST':
form = IPAddressForm(request.POST)
if form.is_valid():
ipaddress = form.save()
messages.success(request, "Created new IP Address: {0}".format(ipaddress))
if '_addanother' in request.POST:
return redirect('ipam:ipaddress_add')
else:
return redirect('ipam:ipaddress', pk=ipaddress.pk)
else:
form = IPAddressForm(initial={
'ipaddress': request.GET.get('ipaddress', None),
})
return render(request, 'ipam/ipaddress_edit.html', {
'form': form,
'cancel_url': reverse('ipam:ipaddress_list'),
})
@permission_required('ipam.change_ipaddress')
def ipaddress_edit(request, pk):
ipaddress = get_object_or_404(IPAddress, pk=pk)
if request.method == 'POST':
form = IPAddressForm(request.POST, instance=ipaddress)
if form.is_valid():
ipaddress = form.save()
messages.success(request, "Modified IP address {0}".format(ipaddress))
return redirect('ipam:ipaddress', pk=ipaddress.pk)
else:
form = IPAddressForm(instance=ipaddress)
return render(request, 'ipam/ipaddress_edit.html', {
'ipaddress': ipaddress,
'form': form,
'cancel_url': reverse('ipam:ipaddress', kwargs={'pk': ipaddress.pk}),
})
@permission_required('ipam.delete_ipaddress')
def ipaddress_delete(request, pk):
ipaddress = get_object_or_404(IPAddress, pk=pk)
if request.method == 'POST':
form = ConfirmationForm(request.POST)
if form.is_valid():
try:
ipaddress.delete()
messages.success(request, "IP address {0} has been deleted".format(ipaddress))
if ipaddress.interface:
return redirect('dcim:device', pk=ipaddress.interface.device.pk)
else:
return redirect('ipam:ipaddress_list')
except ProtectedError, e:
handle_protectederror(ipaddress, request, e)
return redirect('ipam:ipaddress', pk=ipaddress.pk)
else:
form = ConfirmationForm()
# Upon cancellation, redirect to the assigned device if one exists
if ipaddress.interface:
cancel_url = reverse('dcim:device', kwargs={'pk': ipaddress.interface.device.pk})
else:
cancel_url = reverse('ipam:ipaddress_list')
return render(request, 'ipam/ipaddress_delete.html', {
'ipaddress': ipaddress,
'form': form,
'cancel_url': cancel_url,
})
class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):
permission_required = 'ipam.add_ipaddress'
form = IPAddressImportForm
table = IPAddressTable
template_name = 'ipam/ipaddress_import.html'
obj_list_url = 'ipam:ipaddress_list'
def save_obj(self, obj):
obj.save()
# Update primary IP for device if needed
try:
device = obj.primary_for
device.primary_ip = obj
device.save()
except Device.DoesNotExist:
pass
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_ipaddress'
cls = IPAddress
form = IPAddressBulkEditForm
template_name = 'ipam/ipaddress_bulk_edit.html'
redirect_url = 'ipam:ipaddress_list'
def update_objects(self, pk_list, form):
fields_to_update = {}
if form.cleaned_data['vrf']:
fields_to_update['vrf'] = form.cleaned_data['vrf']
elif form.cleaned_data['vrf_global']:
fields_to_update['vrf'] = None
for field in ['description']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
messages.success(self.request, "Updated {} IP addresses".format(updated_count))
class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_ipaddress'
cls = IPAddress
form = IPAddressBulkDeleteForm
template_name = 'ipam/ipaddress_bulk_delete.html'
redirect_url = 'ipam:ipaddress_list'
#
# VLANs
#
class VLANListView(ObjectListView):
queryset = VLAN.objects.select_related('site', 'status', 'role')
filter = VLANFilter
filter_form = VLANFilterForm
table = VLANTable
edit_table = VLANBulkEditTable
edit_table_permissions = ['ipam.change_vlan', 'ipam.delete_vlan']
template_name = 'ipam/vlan_list.html'
def vlan(request, pk):
vlan = get_object_or_404(VLAN.objects.select_related('site', 'status', 'role'), pk=pk)
prefixes = Prefix.objects.filter(vlan=vlan)
return render(request, 'ipam/vlan.html', {
'vlan': vlan,
'prefixes': prefixes,
})
@permission_required('ipam.add_vlan')
def vlan_add(request):
if request.method == 'POST':
form = VLANForm(request.POST)
if form.is_valid():
vlan = form.save()
messages.success(request, "Added new VLAN: {0}".format(vlan))
if '_addanother' in request.POST:
base_url = reverse('ipam:vlan_add')
params = urlencode({
'site': vlan.site.pk,
})
return HttpResponseRedirect('{}?{}'.format(base_url, params))
else:
return redirect('ipam:vlan', pk=vlan.pk)
else:
form = VLANForm()
return render(request, 'ipam/vlan_edit.html', {
'form': form,
'cancel_url': reverse('ipam:vlan_list'),
})
@permission_required('ipam.change_vlan')
def vlan_edit(request, pk):
vlan = get_object_or_404(VLAN, pk=pk)
if request.method == 'POST':
form = VLANForm(request.POST, instance=vlan)
if form.is_valid():
vlan = form.save()
messages.success(request, "Modified VLAN {0}".format(vlan))
return redirect('ipam:vlan', pk=vlan.pk)
else:
form = VLANForm(instance=vlan)
return render(request, 'ipam/vlan_edit.html', {
'vlan': vlan,
'form': form,
'cancel_url': reverse('ipam:vlan', kwargs={'pk': vlan.pk}),
})
@permission_required('ipam.delete_vlan')
def vlan_delete(request, pk):
vlan = get_object_or_404(VLAN, pk=pk)
if request.method == 'POST':
form = ConfirmationForm(request.POST)
if form.is_valid():
try:
vlan.delete()
messages.success(request, "VLAN {0} has been deleted".format(vlan))
return redirect('ipam:vlan_list')
except ProtectedError, e:
handle_protectederror(vlan, request, e)
return redirect('ipam:vlan', pk=vlan.pk)
else:
form = ConfirmationForm()
return render(request, 'ipam/vlan_delete.html', {
'vlan': vlan,
'form': form,
'cancel_url': reverse('ipam:vlan', kwargs={'pk': vlan.pk})
})
class VLANBulkImportView(PermissionRequiredMixin, BulkImportView):
permission_required = 'ipam.add_vlan'
form = VLANImportForm
table = VLANTable
template_name = 'ipam/vlan_import.html'
obj_list_url = 'ipam:vlan_list'
class VLANBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_vlan'
cls = VLAN
form = VLANBulkEditForm
template_name = 'ipam/vlan_bulk_edit.html'
redirect_url = 'ipam:vlan_list'
def update_objects(self, pk_list, form):
fields_to_update = {}
for field in ['site', 'status', 'role']:
if form.cleaned_data[field]:
fields_to_update[field] = form.cleaned_data[field]
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
messages.success(self.request, "Updated {} VLANs".format(updated_count))
class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_vlan'
cls = VLAN
form = VLANBulkDeleteForm
template_name = 'ipam/vlan_bulk_delete.html'
redirect_url = 'ipam:vlan_list'