Converted all object views to class-based views

This commit is contained in:
Jeremy Stretch 2017-05-18 17:00:57 -04:00
parent c454bfcd84
commit fb85867d72
10 changed files with 487 additions and 391 deletions

View File

@ -12,7 +12,7 @@ urlpatterns = [
url(r'^providers/import/$', views.ProviderBulkImportView.as_view(), name='provider_import'), url(r'^providers/import/$', views.ProviderBulkImportView.as_view(), name='provider_import'),
url(r'^providers/edit/$', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'), url(r'^providers/edit/$', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
url(r'^providers/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'), url(r'^providers/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
url(r'^providers/(?P<slug>[\w-]+)/$', views.provider, name='provider'), url(r'^providers/(?P<slug>[\w-]+)/$', views.ProviderView.as_view(), name='provider'),
url(r'^providers/(?P<slug>[\w-]+)/edit/$', views.ProviderEditView.as_view(), name='provider_edit'), url(r'^providers/(?P<slug>[\w-]+)/edit/$', views.ProviderEditView.as_view(), name='provider_edit'),
url(r'^providers/(?P<slug>[\w-]+)/delete/$', views.ProviderDeleteView.as_view(), name='provider_delete'), url(r'^providers/(?P<slug>[\w-]+)/delete/$', views.ProviderDeleteView.as_view(), name='provider_delete'),
@ -28,7 +28,7 @@ urlpatterns = [
url(r'^circuits/import/$', views.CircuitBulkImportView.as_view(), name='circuit_import'), url(r'^circuits/import/$', views.CircuitBulkImportView.as_view(), name='circuit_import'),
url(r'^circuits/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'), url(r'^circuits/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'), url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
url(r'^circuits/(?P<pk>\d+)/$', views.circuit, name='circuit'), url(r'^circuits/(?P<pk>\d+)/$', views.CircuitView.as_view(), name='circuit'),
url(r'^circuits/(?P<pk>\d+)/edit/$', views.CircuitEditView.as_view(), name='circuit_edit'), url(r'^circuits/(?P<pk>\d+)/edit/$', views.CircuitEditView.as_view(), name='circuit_edit'),
url(r'^circuits/(?P<pk>\d+)/delete/$', views.CircuitDeleteView.as_view(), name='circuit_delete'), url(r'^circuits/(?P<pk>\d+)/delete/$', views.CircuitDeleteView.as_view(), name='circuit_delete'),
url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'), url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'),

View File

@ -5,6 +5,7 @@ from django.db import transaction
from django.db.models import Count from django.db.models import Count
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
from django.views.generic import View
from extras.models import Graph, GRAPH_TYPE_PROVIDER from extras.models import Graph, GRAPH_TYPE_PROVIDER
from utilities.forms import ConfirmationForm from utilities.forms import ConfirmationForm
@ -28,18 +29,23 @@ class ProviderListView(ObjectListView):
template_name = 'circuits/provider_list.html' template_name = 'circuits/provider_list.html'
def provider(request, slug): class ProviderView(View):
provider = get_object_or_404(Provider, slug=slug) def get(self, request, slug):
circuits = Circuit.objects.filter(provider=provider).select_related('type', 'tenant')\
.prefetch_related('terminations__site')
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
return render(request, 'circuits/provider.html', { provider = get_object_or_404(Provider, slug=slug)
'provider': provider, circuits = Circuit.objects.filter(provider=provider).select_related(
'circuits': circuits, 'type', 'tenant'
'show_graphs': show_graphs, ).prefetch_related(
}) 'terminations__site'
)
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
return render(request, 'circuits/provider.html', {
'provider': provider,
'circuits': circuits,
'show_graphs': show_graphs,
})
class ProviderEditView(PermissionRequiredMixin, ObjectEditView): class ProviderEditView(PermissionRequiredMixin, ObjectEditView):
@ -117,25 +123,27 @@ class CircuitListView(ObjectListView):
template_name = 'circuits/circuit_list.html' template_name = 'circuits/circuit_list.html'
def circuit(request, pk): class CircuitView(View):
circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk) def get(self, request, pk):
termination_a = CircuitTermination.objects.select_related(
'site__region', 'interface__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_A
).first()
termination_z = CircuitTermination.objects.select_related(
'site__region', 'interface__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_Z
).first()
return render(request, 'circuits/circuit.html', { circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)
'circuit': circuit, termination_a = CircuitTermination.objects.select_related(
'termination_a': termination_a, 'site__region', 'interface__device'
'termination_z': termination_z, ).filter(
}) circuit=circuit, term_side=TERM_SIDE_A
).first()
termination_z = CircuitTermination.objects.select_related(
'site__region', 'interface__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_Z
).first()
return render(request, 'circuits/circuit.html', {
'circuit': circuit,
'termination_a': termination_a,
'termination_z': termination_z,
})
class CircuitEditView(PermissionRequiredMixin, ObjectEditView): class CircuitEditView(PermissionRequiredMixin, ObjectEditView):

View File

@ -22,7 +22,7 @@ urlpatterns = [
url(r'^sites/add/$', views.SiteEditView.as_view(), name='site_add'), url(r'^sites/add/$', views.SiteEditView.as_view(), name='site_add'),
url(r'^sites/import/$', views.SiteBulkImportView.as_view(), name='site_import'), url(r'^sites/import/$', views.SiteBulkImportView.as_view(), name='site_import'),
url(r'^sites/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'), url(r'^sites/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
url(r'^sites/(?P<slug>[\w-]+)/$', views.site, name='site'), url(r'^sites/(?P<slug>[\w-]+)/$', views.SiteView.as_view(), name='site'),
url(r'^sites/(?P<slug>[\w-]+)/edit/$', views.SiteEditView.as_view(), name='site_edit'), url(r'^sites/(?P<slug>[\w-]+)/edit/$', views.SiteEditView.as_view(), name='site_edit'),
url(r'^sites/(?P<slug>[\w-]+)/delete/$', views.SiteDeleteView.as_view(), name='site_delete'), url(r'^sites/(?P<slug>[\w-]+)/delete/$', views.SiteDeleteView.as_view(), name='site_delete'),
url(r'^sites/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}), url(r'^sites/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}),
@ -52,7 +52,7 @@ urlpatterns = [
url(r'^racks/import/$', views.RackBulkImportView.as_view(), name='rack_import'), url(r'^racks/import/$', views.RackBulkImportView.as_view(), name='rack_import'),
url(r'^racks/edit/$', views.RackBulkEditView.as_view(), name='rack_bulk_edit'), url(r'^racks/edit/$', views.RackBulkEditView.as_view(), name='rack_bulk_edit'),
url(r'^racks/delete/$', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'), url(r'^racks/delete/$', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'),
url(r'^racks/(?P<pk>\d+)/$', views.rack, name='rack'), url(r'^racks/(?P<pk>\d+)/$', views.RackView.as_view(), name='rack'),
url(r'^racks/(?P<pk>\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'), url(r'^racks/(?P<pk>\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'),
url(r'^racks/(?P<pk>\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'), url(r'^racks/(?P<pk>\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'),
url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationEditView.as_view(), name='rack_add_reservation'), url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationEditView.as_view(), name='rack_add_reservation'),
@ -69,7 +69,7 @@ urlpatterns = [
url(r'^device-types/add/$', views.DeviceTypeEditView.as_view(), name='devicetype_add'), url(r'^device-types/add/$', views.DeviceTypeEditView.as_view(), name='devicetype_add'),
url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'), url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'), url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
url(r'^device-types/(?P<pk>\d+)/$', views.devicetype, name='devicetype'), url(r'^device-types/(?P<pk>\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'),
url(r'^device-types/(?P<pk>\d+)/edit/$', views.DeviceTypeEditView.as_view(), name='devicetype_edit'), url(r'^device-types/(?P<pk>\d+)/edit/$', views.DeviceTypeEditView.as_view(), name='devicetype_edit'),
url(r'^device-types/(?P<pk>\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'), url(r'^device-types/(?P<pk>\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'),
@ -117,11 +117,11 @@ urlpatterns = [
url(r'^devices/import/child-devices/$', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'), url(r'^devices/import/child-devices/$', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'),
url(r'^devices/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'), url(r'^devices/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
url(r'^devices/delete/$', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'), url(r'^devices/delete/$', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'),
url(r'^devices/(?P<pk>\d+)/$', views.device, name='device'), url(r'^devices/(?P<pk>\d+)/$', views.DeviceView.as_view(), name='device'),
url(r'^devices/(?P<pk>\d+)/edit/$', views.DeviceEditView.as_view(), name='device_edit'), url(r'^devices/(?P<pk>\d+)/edit/$', views.DeviceEditView.as_view(), name='device_edit'),
url(r'^devices/(?P<pk>\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'), url(r'^devices/(?P<pk>\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'),
url(r'^devices/(?P<pk>\d+)/inventory/$', views.device_inventory, name='device_inventory'), url(r'^devices/(?P<pk>\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'),
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.device_lldp_neighbors, name='device_lldp_neighbors'), url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
url(r'^devices/(?P<pk>\d+)/add-secret/$', secret_add, name='device_addsecret'), url(r'^devices/(?P<pk>\d+)/add-secret/$', secret_add, name='device_addsecret'),
url(r'^devices/(?P<device>\d+)/services/assign/$', ServiceEditView.as_view(), name='service_assign'), url(r'^devices/(?P<device>\d+)/services/assign/$', ServiceEditView.as_view(), name='service_assign'),
url(r'^devices/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}), url(r'^devices/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}),

View File

@ -178,27 +178,29 @@ class SiteListView(ObjectListView):
template_name = 'dcim/site_list.html' template_name = 'dcim/site_list.html'
def site(request, slug): class SiteView(View):
site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=slug) def get(self, request, slug):
stats = {
'rack_count': Rack.objects.filter(site=site).count(),
'device_count': Device.objects.filter(site=site).count(),
'prefix_count': Prefix.objects.filter(site=site).count(),
'vlan_count': VLAN.objects.filter(site=site).count(),
'circuit_count': Circuit.objects.filter(terminations__site=site).count(),
}
rack_groups = RackGroup.objects.filter(site=site).annotate(rack_count=Count('racks'))
topology_maps = TopologyMap.objects.filter(site=site)
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_SITE).exists()
return render(request, 'dcim/site.html', { site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=slug)
'site': site, stats = {
'stats': stats, 'rack_count': Rack.objects.filter(site=site).count(),
'rack_groups': rack_groups, 'device_count': Device.objects.filter(site=site).count(),
'topology_maps': topology_maps, 'prefix_count': Prefix.objects.filter(site=site).count(),
'show_graphs': show_graphs, 'vlan_count': VLAN.objects.filter(site=site).count(),
}) 'circuit_count': Circuit.objects.filter(terminations__site=site).count(),
}
rack_groups = RackGroup.objects.filter(site=site).annotate(rack_count=Count('racks'))
topology_maps = TopologyMap.objects.filter(site=site)
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_SITE).exists()
return render(request, 'dcim/site.html', {
'site': site,
'stats': stats,
'rack_groups': rack_groups,
'topology_maps': topology_maps,
'show_graphs': show_graphs,
})
class SiteEditView(PermissionRequiredMixin, ObjectEditView): class SiteEditView(PermissionRequiredMixin, ObjectEditView):
@ -290,8 +292,13 @@ class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
# #
class RackListView(ObjectListView): class RackListView(ObjectListView):
queryset = Rack.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('devices__device_type')\ queryset = Rack.objects.select_related(
.annotate(device_count=Count('devices', distinct=True)) 'site', 'group', 'tenant', 'role'
).prefetch_related(
'devices__device_type'
).annotate(
device_count=Count('devices', distinct=True)
)
filter = filters.RackFilter filter = filters.RackFilter
filter_form = forms.RackFilterForm filter_form = forms.RackFilterForm
table = tables.RackTable table = tables.RackTable
@ -338,31 +345,33 @@ class RackElevationListView(View):
}) })
def rack(request, pk): class RackView(View):
rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk) def get(self, request, pk):
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True)\ rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
.select_related('device_type__manufacturer')
next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name').first()
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
reservations = RackReservation.objects.filter(rack=rack) nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True)\
reserved_units = {} .select_related('device_type__manufacturer')
for r in reservations: next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name').first()
for u in r.units: prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
reserved_units[u] = r
return render(request, 'dcim/rack.html', { reservations = RackReservation.objects.filter(rack=rack)
'rack': rack, reserved_units = {}
'reservations': reservations, for r in reservations:
'reserved_units': reserved_units, for u in r.units:
'nonracked_devices': nonracked_devices, reserved_units[u] = r
'next_rack': next_rack,
'prev_rack': prev_rack, return render(request, 'dcim/rack.html', {
'front_elevation': rack.get_front_elevation(), 'rack': rack,
'rear_elevation': rack.get_rear_elevation(), 'reservations': reservations,
}) 'reserved_units': reserved_units,
'nonracked_devices': nonracked_devices,
'next_rack': next_rack,
'prev_rack': prev_rack,
'front_elevation': rack.get_front_elevation(),
'rear_elevation': rack.get_rear_elevation(),
})
class RackEditView(PermissionRequiredMixin, ObjectEditView): class RackEditView(PermissionRequiredMixin, ObjectEditView):
@ -481,53 +490,57 @@ class DeviceTypeListView(ObjectListView):
template_name = 'dcim/devicetype_list.html' template_name = 'dcim/devicetype_list.html'
def devicetype(request, pk): class DeviceTypeView(View):
devicetype = get_object_or_404(DeviceType, pk=pk) def get(self, request, pk):
# Component tables devicetype = get_object_or_404(DeviceType, pk=pk)
consoleport_table = tables.ConsolePortTemplateTable(
natsorted(ConsolePortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
consoleserverport_table = tables.ConsoleServerPortTemplateTable(
natsorted(ConsoleServerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
powerport_table = tables.PowerPortTemplateTable(
natsorted(PowerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
poweroutlet_table = tables.PowerOutletTemplateTable(
natsorted(PowerOutletTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
mgmt_interface_table = tables.InterfaceTemplateTable(
list(InterfaceTemplate.objects.order_naturally(devicetype.interface_ordering).filter(device_type=devicetype,
mgmt_only=True))
)
interface_table = tables.InterfaceTemplateTable(
list(InterfaceTemplate.objects.order_naturally(devicetype.interface_ordering).filter(device_type=devicetype,
mgmt_only=False))
)
devicebay_table = tables.DeviceBayTemplateTable(
natsorted(DeviceBayTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
if request.user.has_perm('dcim.change_devicetype'):
consoleport_table.base_columns['pk'].visible = True
consoleserverport_table.base_columns['pk'].visible = True
powerport_table.base_columns['pk'].visible = True
poweroutlet_table.base_columns['pk'].visible = True
mgmt_interface_table.base_columns['pk'].visible = True
interface_table.base_columns['pk'].visible = True
devicebay_table.base_columns['pk'].visible = True
return render(request, 'dcim/devicetype.html', { # Component tables
'devicetype': devicetype, consoleport_table = tables.ConsolePortTemplateTable(
'consoleport_table': consoleport_table, natsorted(ConsolePortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
'consoleserverport_table': consoleserverport_table, )
'powerport_table': powerport_table, consoleserverport_table = tables.ConsoleServerPortTemplateTable(
'poweroutlet_table': poweroutlet_table, natsorted(ConsoleServerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
'mgmt_interface_table': mgmt_interface_table, )
'interface_table': interface_table, powerport_table = tables.PowerPortTemplateTable(
'devicebay_table': devicebay_table, natsorted(PowerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
}) )
poweroutlet_table = tables.PowerOutletTemplateTable(
natsorted(PowerOutletTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
mgmt_interface_table = tables.InterfaceTemplateTable(
list(InterfaceTemplate.objects.order_naturally(devicetype.interface_ordering).filter(
device_type=devicetype, mgmt_only=True
))
)
interface_table = tables.InterfaceTemplateTable(
list(InterfaceTemplate.objects.order_naturally(devicetype.interface_ordering).filter(
device_type=devicetype, mgmt_only=False
))
)
devicebay_table = tables.DeviceBayTemplateTable(
natsorted(DeviceBayTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
)
if request.user.has_perm('dcim.change_devicetype'):
consoleport_table.base_columns['pk'].visible = True
consoleserverport_table.base_columns['pk'].visible = True
powerport_table.base_columns['pk'].visible = True
poweroutlet_table.base_columns['pk'].visible = True
mgmt_interface_table.base_columns['pk'].visible = True
interface_table.base_columns['pk'].visible = True
devicebay_table.base_columns['pk'].visible = True
return render(request, 'dcim/devicetype.html', {
'devicetype': devicetype,
'consoleport_table': consoleport_table,
'consoleserverport_table': consoleserverport_table,
'powerport_table': powerport_table,
'poweroutlet_table': poweroutlet_table,
'mgmt_interface_table': mgmt_interface_table,
'interface_table': interface_table,
'devicebay_table': devicebay_table,
})
class DeviceTypeEditView(PermissionRequiredMixin, ObjectEditView): class DeviceTypeEditView(PermissionRequiredMixin, ObjectEditView):
@ -727,70 +740,114 @@ class DeviceListView(ObjectListView):
template_name = 'dcim/device_list.html' template_name = 'dcim/device_list.html'
def device(request, pk): class DeviceView(View):
device = get_object_or_404(Device.objects.select_related( def get(self, request, pk):
'site__region', 'rack__group', 'tenant__group', 'device_role', 'platform'
), pk=pk)
console_ports = natsorted(
ConsolePort.objects.filter(device=device).select_related('cs_port__device'), key=attrgetter('name')
)
cs_ports = natsorted(
ConsoleServerPort.objects.filter(device=device).select_related('connected_console'), key=attrgetter('name')
)
power_ports = natsorted(
PowerPort.objects.filter(device=device).select_related('power_outlet__device'), key=attrgetter('name')
)
power_outlets = natsorted(
PowerOutlet.objects.filter(device=device).select_related('connected_port'), key=attrgetter('name')
)
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
.filter(device=device, mgmt_only=False)\
.select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit').prefetch_related('ip_addresses')
mgmt_interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
.filter(device=device, mgmt_only=True)\
.select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit').prefetch_related('ip_addresses')
device_bays = natsorted(
DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer'),
key=attrgetter('name')
)
services = Service.objects.filter(device=device)
secrets = device.secrets.all()
# Find any related devices for convenient linking in the UI device = get_object_or_404(Device.objects.select_related(
related_devices = [] 'site__region', 'rack__group', 'tenant__group', 'device_role', 'platform'
if device.name: ), pk=pk)
if re.match('.+[0-9]+$', device.name): console_ports = natsorted(
# Strip 1 or more trailing digits (e.g. core-switch1) ConsolePort.objects.filter(device=device).select_related('cs_port__device'), key=attrgetter('name')
base_name = re.match('(.*?)[0-9]+$', device.name).group(1) )
elif re.match('.+\d[a-z]$', device.name.lower()): cs_ports = natsorted(
# Strip a trailing letter if preceded by a digit (e.g. dist-switch3a -> dist-switch3) ConsoleServerPort.objects.filter(device=device).select_related('connected_console'), key=attrgetter('name')
base_name = re.match('(.*\d+)[a-z]$', device.name.lower()).group(1) )
else: power_ports = natsorted(
base_name = None PowerPort.objects.filter(device=device).select_related('power_outlet__device'), key=attrgetter('name')
if base_name: )
related_devices = Device.objects.filter(name__istartswith=base_name).exclude(pk=device.pk)\ power_outlets = natsorted(
.select_related('rack', 'device_type__manufacturer')[:10] PowerOutlet.objects.filter(device=device).select_related('connected_port'), key=attrgetter('name')
)
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(
device=device, mgmt_only=False
).select_related(
'connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit'
).prefetch_related('ip_addresses')
mgmt_interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(
device=device, mgmt_only=True
).select_related(
'connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit'
).prefetch_related('ip_addresses')
device_bays = natsorted(
DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer'),
key=attrgetter('name')
)
services = Service.objects.filter(device=device)
secrets = device.secrets.all()
# Show graph button on interfaces only if at least one graph has been created. # Find any related devices for convenient linking in the UI
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists() related_devices = []
if device.name:
if re.match('.+[0-9]+$', device.name):
# Strip 1 or more trailing digits (e.g. core-switch1)
base_name = re.match('(.*?)[0-9]+$', device.name).group(1)
elif re.match('.+\d[a-z]$', device.name.lower()):
# Strip a trailing letter if preceded by a digit (e.g. dist-switch3a -> dist-switch3)
base_name = re.match('(.*\d+)[a-z]$', device.name.lower()).group(1)
else:
base_name = None
if base_name:
related_devices = Device.objects.filter(name__istartswith=base_name).exclude(pk=device.pk)\
.select_related('rack', 'device_type__manufacturer')[:10]
return render(request, 'dcim/device.html', { # Show graph button on interfaces only if at least one graph has been created.
'device': device, show_graphs = Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists()
'console_ports': console_ports,
'cs_ports': cs_ports, return render(request, 'dcim/device.html', {
'power_ports': power_ports, 'device': device,
'power_outlets': power_outlets, 'console_ports': console_ports,
'interfaces': interfaces, 'cs_ports': cs_ports,
'mgmt_interfaces': mgmt_interfaces, 'power_ports': power_ports,
'device_bays': device_bays, 'power_outlets': power_outlets,
'services': services, 'interfaces': interfaces,
'secrets': secrets, 'mgmt_interfaces': mgmt_interfaces,
'related_devices': related_devices, 'device_bays': device_bays,
'show_graphs': show_graphs, 'services': services,
}) 'secrets': secrets,
'related_devices': related_devices,
'show_graphs': show_graphs,
})
class DeviceInventoryView(View):
def get(self, request, pk):
device = get_object_or_404(Device, pk=pk)
inventory_items = InventoryItem.objects.filter(
device=device, parent=None
).select_related(
'manufacturer'
).prefetch_related(
'child_items'
)
return render(request, 'dcim/device_inventory.html', {
'device': device,
'inventory_items': inventory_items,
})
class DeviceLLDPNeighborsView(View):
def get(self, request, pk):
device = get_object_or_404(Device, pk=pk)
interfaces = Interface.objects.order_naturally(
device.device_type.interface_ordering
).filter(
device=device
).select_related(
'connected_as_a', 'connected_as_b'
)
return render(request, 'dcim/device_lldp_neighbors.html', {
'device': device,
'interfaces': interfaces,
})
class DeviceEditView(PermissionRequiredMixin, ObjectEditView): class DeviceEditView(PermissionRequiredMixin, ObjectEditView):
@ -851,30 +908,6 @@ class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
def device_inventory(request, pk):
device = get_object_or_404(Device, pk=pk)
inventory_items = InventoryItem.objects.filter(device=device, parent=None).select_related('manufacturer')\
.prefetch_related('child_items')
return render(request, 'dcim/device_inventory.html', {
'device': device,
'inventory_items': inventory_items,
})
def device_lldp_neighbors(request, pk):
device = get_object_or_404(Device, pk=pk)
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(device=device)\
.select_related('connected_as_a', 'connected_as_b')
return render(request, 'dcim/device_lldp_neighbors.html', {
'device': device,
'interfaces': interfaces,
})
# #
# Console ports # Console ports
# #

View File

@ -12,7 +12,7 @@ urlpatterns = [
url(r'^vrfs/import/$', views.VRFBulkImportView.as_view(), name='vrf_import'), url(r'^vrfs/import/$', views.VRFBulkImportView.as_view(), name='vrf_import'),
url(r'^vrfs/edit/$', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'), url(r'^vrfs/edit/$', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'),
url(r'^vrfs/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'), url(r'^vrfs/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'),
url(r'^vrfs/(?P<pk>\d+)/$', views.vrf, name='vrf'), url(r'^vrfs/(?P<pk>\d+)/$', views.VRFView.as_view(), name='vrf'),
url(r'^vrfs/(?P<pk>\d+)/edit/$', views.VRFEditView.as_view(), name='vrf_edit'), url(r'^vrfs/(?P<pk>\d+)/edit/$', views.VRFEditView.as_view(), name='vrf_edit'),
url(r'^vrfs/(?P<pk>\d+)/delete/$', views.VRFDeleteView.as_view(), name='vrf_delete'), url(r'^vrfs/(?P<pk>\d+)/delete/$', views.VRFDeleteView.as_view(), name='vrf_delete'),
@ -28,7 +28,7 @@ urlpatterns = [
url(r'^aggregates/import/$', views.AggregateBulkImportView.as_view(), name='aggregate_import'), url(r'^aggregates/import/$', views.AggregateBulkImportView.as_view(), name='aggregate_import'),
url(r'^aggregates/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'), url(r'^aggregates/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'),
url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'), url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'),
url(r'^aggregates/(?P<pk>\d+)/$', views.aggregate, name='aggregate'), url(r'^aggregates/(?P<pk>\d+)/$', views.AggregateView.as_view(), name='aggregate'),
url(r'^aggregates/(?P<pk>\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'), url(r'^aggregates/(?P<pk>\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'),
url(r'^aggregates/(?P<pk>\d+)/delete/$', views.AggregateDeleteView.as_view(), name='aggregate_delete'), url(r'^aggregates/(?P<pk>\d+)/delete/$', views.AggregateDeleteView.as_view(), name='aggregate_delete'),
@ -44,10 +44,10 @@ urlpatterns = [
url(r'^prefixes/import/$', views.PrefixBulkImportView.as_view(), name='prefix_import'), url(r'^prefixes/import/$', views.PrefixBulkImportView.as_view(), name='prefix_import'),
url(r'^prefixes/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), url(r'^prefixes/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'),
url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'),
url(r'^prefixes/(?P<pk>\d+)/$', views.prefix, name='prefix'), url(r'^prefixes/(?P<pk>\d+)/$', views.PrefixView.as_view(), name='prefix'),
url(r'^prefixes/(?P<pk>\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'), url(r'^prefixes/(?P<pk>\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'),
url(r'^prefixes/(?P<pk>\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'), url(r'^prefixes/(?P<pk>\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'),
url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', views.prefix_ipaddresses, name='prefix_ipaddresses'), url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'),
# IP addresses # IP addresses
url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'), url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'),
@ -56,7 +56,7 @@ urlpatterns = [
url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'), url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'),
url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'), url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'),
url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'), url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'),
url(r'^ip-addresses/(?P<pk>\d+)/$', views.ipaddress, name='ipaddress'), url(r'^ip-addresses/(?P<pk>\d+)/$', views.IPAddressView.as_view(), name='ipaddress'),
url(r'^ip-addresses/(?P<pk>\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'), url(r'^ip-addresses/(?P<pk>\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'),
url(r'^ip-addresses/(?P<pk>\d+)/delete/$', views.IPAddressDeleteView.as_view(), name='ipaddress_delete'), url(r'^ip-addresses/(?P<pk>\d+)/delete/$', views.IPAddressDeleteView.as_view(), name='ipaddress_delete'),
@ -72,7 +72,7 @@ urlpatterns = [
url(r'^vlans/import/$', views.VLANBulkImportView.as_view(), name='vlan_import'), url(r'^vlans/import/$', views.VLANBulkImportView.as_view(), name='vlan_import'),
url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'), url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'),
url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'), url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'),
url(r'^vlans/(?P<pk>\d+)/$', views.vlan, name='vlan'), url(r'^vlans/(?P<pk>\d+)/$', views.VLANView.as_view(), name='vlan'),
url(r'^vlans/(?P<pk>\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'), url(r'^vlans/(?P<pk>\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'),
url(r'^vlans/(?P<pk>\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'), url(r'^vlans/(?P<pk>\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'),

View File

@ -6,6 +6,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Count, Q from django.db.models import Count, Q
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.urls import reverse from django.urls import reverse
from django.views.generic import View
from dcim.models import Device from dcim.models import Device
from utilities.paginator import EnhancedPaginator from utilities.paginator import EnhancedPaginator
@ -96,18 +97,20 @@ class VRFListView(ObjectListView):
template_name = 'ipam/vrf_list.html' template_name = 'ipam/vrf_list.html'
def vrf(request, pk): class VRFView(View):
vrf = get_object_or_404(VRF.objects.all(), pk=pk) def get(self, request, pk):
prefix_table = tables.PrefixBriefTable(
list(Prefix.objects.filter(vrf=vrf).select_related('site', 'role'))
)
prefix_table.exclude = ('vrf',)
return render(request, 'ipam/vrf.html', { vrf = get_object_or_404(VRF.objects.all(), pk=pk)
'vrf': vrf, prefix_table = tables.PrefixBriefTable(
'prefix_table': prefix_table, list(Prefix.objects.filter(vrf=vrf).select_related('site', 'role'))
}) )
prefix_table.exclude = ('vrf',)
return render(request, 'ipam/vrf.html', {
'vrf': vrf,
'prefix_table': prefix_table,
})
class VRFEditView(PermissionRequiredMixin, ObjectEditView): class VRFEditView(PermissionRequiredMixin, ObjectEditView):
@ -281,37 +284,44 @@ class AggregateListView(ObjectListView):
} }
def aggregate(request, pk): class AggregateView(View):
aggregate = get_object_or_404(Aggregate, pk=pk) def get(self, request, pk):
# Find all child prefixes contained by this aggregate aggregate = get_object_or_404(Aggregate, pk=pk)
child_prefixes = Prefix.objects.filter(prefix__net_contained_or_equal=str(aggregate.prefix))\
.select_related('site', 'role').annotate_depth(limit=0)
child_prefixes = add_available_prefixes(aggregate.prefix, child_prefixes)
prefix_table = tables.PrefixTable(child_prefixes) # Find all child prefixes contained by this aggregate
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): child_prefixes = Prefix.objects.filter(
prefix_table.base_columns['pk'].visible = True prefix__net_contained_or_equal=str(aggregate.prefix)
).select_related(
'site', 'role'
).annotate_depth(
limit=0
)
child_prefixes = add_available_prefixes(aggregate.prefix, child_prefixes)
paginate = { prefix_table = tables.PrefixTable(child_prefixes)
'klass': EnhancedPaginator, if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) prefix_table.base_columns['pk'].visible = True
}
RequestConfig(request, paginate).configure(prefix_table)
# Compile permissions list for rendering the object table paginate = {
permissions = { 'klass': EnhancedPaginator,
'add': request.user.has_perm('ipam.add_prefix'), 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
'change': request.user.has_perm('ipam.change_prefix'), }
'delete': request.user.has_perm('ipam.delete_prefix'), RequestConfig(request, paginate).configure(prefix_table)
}
return render(request, 'ipam/aggregate.html', { # Compile permissions list for rendering the object table
'aggregate': aggregate, permissions = {
'prefix_table': prefix_table, 'add': request.user.has_perm('ipam.add_prefix'),
'permissions': permissions, 'change': request.user.has_perm('ipam.change_prefix'),
}) 'delete': request.user.has_perm('ipam.delete_prefix'),
}
return render(request, 'ipam/aggregate.html', {
'aggregate': aggregate,
'prefix_table': prefix_table,
'permissions': permissions,
})
class AggregateEditView(PermissionRequiredMixin, ObjectEditView): class AggregateEditView(PermissionRequiredMixin, ObjectEditView):
@ -394,66 +404,120 @@ class PrefixListView(ObjectListView):
return self.queryset.annotate_depth(limit=limit) return self.queryset.annotate_depth(limit=limit)
def prefix(request, pk): class PrefixView(View):
prefix = get_object_or_404(Prefix.objects.select_related( def get(self, request, pk):
'vrf', 'site__region', 'tenant__group', 'vlan__group', 'role'
), pk=pk)
try: prefix = get_object_or_404(Prefix.objects.select_related(
aggregate = Aggregate.objects.get(prefix__net_contains_or_equals=str(prefix.prefix)) 'vrf', 'site__region', 'tenant__group', 'vlan__group', 'role'
except Aggregate.DoesNotExist: ), pk=pk)
aggregate = None
# Count child IP addresses try:
ipaddress_count = IPAddress.objects.filter(vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix))\ aggregate = Aggregate.objects.get(prefix__net_contains_or_equals=str(prefix.prefix))
.count() except Aggregate.DoesNotExist:
aggregate = None
# Parent prefixes table # Count child IP addresses
parent_prefixes = Prefix.objects.filter(Q(vrf=prefix.vrf) | Q(vrf__isnull=True))\ ipaddress_count = IPAddress.objects.filter(
.filter(prefix__net_contains=str(prefix.prefix))\ vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix)
.select_related('site', 'role').annotate_depth() ).count()
parent_prefix_table = tables.PrefixBriefTable(parent_prefixes)
parent_prefix_table.exclude = ('vrf',)
# Duplicate prefixes table # Parent prefixes table
duplicate_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix=str(prefix.prefix)).exclude(pk=prefix.pk)\ parent_prefixes = Prefix.objects.filter(
.select_related('site', 'role') Q(vrf=prefix.vrf) | Q(vrf__isnull=True)
duplicate_prefix_table = tables.PrefixBriefTable(list(duplicate_prefixes)) ).filter(
duplicate_prefix_table.exclude = ('vrf',) prefix__net_contains=str(prefix.prefix)
).select_related(
'site', 'role'
).annotate_depth()
parent_prefix_table = tables.PrefixBriefTable(parent_prefixes)
parent_prefix_table.exclude = ('vrf',)
# Child prefixes table # Duplicate prefixes table
child_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix))\ duplicate_prefixes = Prefix.objects.filter(
.select_related('site', 'role').annotate_depth(limit=0) vrf=prefix.vrf, prefix=str(prefix.prefix)
if child_prefixes: ).exclude(
child_prefixes = add_available_prefixes(prefix.prefix, child_prefixes) pk=prefix.pk
child_prefix_table = tables.PrefixTable(child_prefixes) ).select_related(
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): 'site', 'role'
child_prefix_table.base_columns['pk'].visible = True )
duplicate_prefix_table = tables.PrefixBriefTable(list(duplicate_prefixes))
duplicate_prefix_table.exclude = ('vrf',)
paginate = { # Child prefixes table
'klass': EnhancedPaginator, child_prefixes = Prefix.objects.filter(
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix)
} ).select_related(
RequestConfig(request, paginate).configure(child_prefix_table) 'site', 'role'
).annotate_depth(limit=0)
if child_prefixes:
child_prefixes = add_available_prefixes(prefix.prefix, child_prefixes)
child_prefix_table = tables.PrefixTable(child_prefixes)
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
child_prefix_table.base_columns['pk'].visible = True
# Compile permissions list for rendering the object table paginate = {
permissions = { 'klass': EnhancedPaginator,
'add': request.user.has_perm('ipam.add_prefix'), 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
'change': request.user.has_perm('ipam.change_prefix'), }
'delete': request.user.has_perm('ipam.delete_prefix'), RequestConfig(request, paginate).configure(child_prefix_table)
}
return render(request, 'ipam/prefix.html', { # Compile permissions list for rendering the object table
'prefix': prefix, permissions = {
'aggregate': aggregate, 'add': request.user.has_perm('ipam.add_prefix'),
'ipaddress_count': ipaddress_count, 'change': request.user.has_perm('ipam.change_prefix'),
'parent_prefix_table': parent_prefix_table, 'delete': request.user.has_perm('ipam.delete_prefix'),
'child_prefix_table': child_prefix_table, }
'duplicate_prefix_table': duplicate_prefix_table,
'permissions': permissions, return render(request, 'ipam/prefix.html', {
'return_url': prefix.get_absolute_url(), '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,
'permissions': permissions,
'return_url': prefix.get_absolute_url(),
})
class PrefixIPAddressesView(View):
def get(self, request, pk):
prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
# Find all IPAddresses belonging to this Prefix
ipaddresses = IPAddress.objects.filter(
vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix)
).select_related(
'vrf', 'interface__device', 'primary_ip4_for', 'primary_ip6_for'
)
ipaddresses = add_available_ipaddresses(prefix.prefix, ipaddresses, prefix.is_pool)
ip_table = tables.IPAddressTable(ipaddresses)
if request.user.has_perm('ipam.change_ipaddress') or request.user.has_perm('ipam.delete_ipaddress'):
ip_table.base_columns['pk'].visible = True
paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(ip_table)
# Compile permissions list for rendering the object table
permissions = {
'add': request.user.has_perm('ipam.add_ipaddress'),
'change': request.user.has_perm('ipam.change_ipaddress'),
'delete': request.user.has_perm('ipam.delete_ipaddress'),
}
return render(request, 'ipam/prefix_ipaddresses.html', {
'prefix': prefix,
'ip_table': ip_table,
'permissions': permissions,
'bulk_querystring': 'vrf_id={}&parent={}'.format(prefix.vrf or '0', prefix.prefix),
})
class PrefixEditView(PermissionRequiredMixin, ObjectEditView): class PrefixEditView(PermissionRequiredMixin, ObjectEditView):
@ -495,40 +559,6 @@ class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
default_return_url = 'ipam:prefix_list' default_return_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(vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix))\
.select_related('vrf', 'interface__device', 'primary_ip4_for', 'primary_ip6_for')
ipaddresses = add_available_ipaddresses(prefix.prefix, ipaddresses, prefix.is_pool)
ip_table = tables.IPAddressTable(ipaddresses)
if request.user.has_perm('ipam.change_ipaddress') or request.user.has_perm('ipam.delete_ipaddress'):
ip_table.base_columns['pk'].visible = True
paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(ip_table)
# Compile permissions list for rendering the object table
permissions = {
'add': request.user.has_perm('ipam.add_ipaddress'),
'change': request.user.has_perm('ipam.change_ipaddress'),
'delete': request.user.has_perm('ipam.delete_ipaddress'),
}
return render(request, 'ipam/prefix_ipaddresses.html', {
'prefix': prefix,
'ip_table': ip_table,
'permissions': permissions,
'bulk_querystring': 'vrf_id={}&parent={}'.format(prefix.vrf or '0', prefix.prefix),
})
# #
# IP addresses # IP addresses
# #
@ -541,32 +571,47 @@ class IPAddressListView(ObjectListView):
template_name = 'ipam/ipaddress_list.html' template_name = 'ipam/ipaddress_list.html'
def ipaddress(request, pk): class IPAddressView(View):
ipaddress = get_object_or_404(IPAddress.objects.select_related('interface__device'), pk=pk) def get(self, request, pk):
# Parent prefixes table 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))\
.select_related('site', 'role')
parent_prefixes_table = tables.PrefixBriefTable(list(parent_prefixes))
parent_prefixes_table.exclude = ('vrf',)
# Duplicate IPs table # Parent prefixes table
duplicate_ips = IPAddress.objects.filter(vrf=ipaddress.vrf, address=str(ipaddress.address))\ parent_prefixes = Prefix.objects.filter(
.exclude(pk=ipaddress.pk).select_related('interface__device', 'nat_inside') vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip)
duplicate_ips_table = tables.IPAddressBriefTable(list(duplicate_ips)) ).select_related(
'site', 'role'
)
parent_prefixes_table = tables.PrefixBriefTable(list(parent_prefixes))
parent_prefixes_table.exclude = ('vrf',)
# Related IP table # Duplicate IPs table
related_ips = IPAddress.objects.select_related('interface__device').exclude(address=str(ipaddress.address))\ duplicate_ips = IPAddress.objects.filter(
.filter(vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address)) vrf=ipaddress.vrf, address=str(ipaddress.address)
related_ips_table = tables.IPAddressBriefTable(list(related_ips)) ).exclude(
pk=ipaddress.pk
).select_related(
'interface__device', 'nat_inside'
)
duplicate_ips_table = tables.IPAddressBriefTable(list(duplicate_ips))
return render(request, 'ipam/ipaddress.html', { # Related IP table
'ipaddress': ipaddress, related_ips = IPAddress.objects.select_related(
'parent_prefixes_table': parent_prefixes_table, 'interface__device'
'duplicate_ips_table': duplicate_ips_table, ).exclude(
'related_ips_table': related_ips_table, address=str(ipaddress.address)
}) ).filter(
vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address)
)
related_ips_table = tables.IPAddressBriefTable(list(related_ips))
return render(request, 'ipam/ipaddress.html', {
'ipaddress': ipaddress,
'parent_prefixes_table': parent_prefixes_table,
'duplicate_ips_table': duplicate_ips_table,
'related_ips_table': related_ips_table,
})
class IPAddressEditView(PermissionRequiredMixin, ObjectEditView): class IPAddressEditView(PermissionRequiredMixin, ObjectEditView):
@ -669,17 +714,21 @@ class VLANListView(ObjectListView):
template_name = 'ipam/vlan_list.html' template_name = 'ipam/vlan_list.html'
def vlan(request, pk): class VLANView(View):
vlan = get_object_or_404(VLAN.objects.select_related('site__region', 'tenant__group', 'role'), pk=pk) def get(self, request, pk):
prefixes = Prefix.objects.filter(vlan=vlan).select_related('vrf', 'site', 'role')
prefix_table = tables.PrefixBriefTable(list(prefixes))
prefix_table.exclude = ('vlan',)
return render(request, 'ipam/vlan.html', { vlan = get_object_or_404(VLAN.objects.select_related(
'vlan': vlan, 'site__region', 'tenant__group', 'role'
'prefix_table': prefix_table, ), pk=pk)
}) prefixes = Prefix.objects.filter(vlan=vlan).select_related('vrf', 'site', 'role')
prefix_table = tables.PrefixBriefTable(list(prefixes))
prefix_table.exclude = ('vlan',)
return render(request, 'ipam/vlan.html', {
'vlan': vlan,
'prefix_table': prefix_table,
})
class VLANEditView(PermissionRequiredMixin, ObjectEditView): class VLANEditView(PermissionRequiredMixin, ObjectEditView):

View File

@ -17,7 +17,7 @@ urlpatterns = [
url(r'^secrets/import/$', views.secret_import, name='secret_import'), url(r'^secrets/import/$', views.secret_import, name='secret_import'),
url(r'^secrets/edit/$', views.SecretBulkEditView.as_view(), name='secret_bulk_edit'), url(r'^secrets/edit/$', views.SecretBulkEditView.as_view(), name='secret_bulk_edit'),
url(r'^secrets/delete/$', views.SecretBulkDeleteView.as_view(), name='secret_bulk_delete'), url(r'^secrets/delete/$', views.SecretBulkDeleteView.as_view(), name='secret_bulk_delete'),
url(r'^secrets/(?P<pk>\d+)/$', views.secret, name='secret'), url(r'^secrets/(?P<pk>\d+)/$', views.SecretView.as_view(), name='secret'),
url(r'^secrets/(?P<pk>\d+)/edit/$', views.secret_edit, name='secret_edit'), url(r'^secrets/(?P<pk>\d+)/edit/$', views.secret_edit, name='secret_edit'),
url(r'^secrets/(?P<pk>\d+)/delete/$', views.SecretDeleteView.as_view(), name='secret_delete'), url(r'^secrets/(?P<pk>\d+)/delete/$', views.SecretDeleteView.as_view(), name='secret_delete'),

View File

@ -8,6 +8,7 @@ from django.db.models import Count
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic import View
from dcim.models import Device from dcim.models import Device
from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
@ -65,14 +66,16 @@ class SecretListView(ObjectListView):
template_name = 'secrets/secret_list.html' template_name = 'secrets/secret_list.html'
@login_required @method_decorator(login_required, name='dispatch')
def secret(request, pk): class SecretView(View):
secret = get_object_or_404(Secret, pk=pk) def get(self, request, pk):
return render(request, 'secrets/secret.html', { secret = get_object_or_404(Secret, pk=pk)
'secret': secret,
}) return render(request, 'secrets/secret.html', {
'secret': secret,
})
@permission_required('secrets.add_secret') @permission_required('secrets.add_secret')

View File

@ -18,7 +18,7 @@ urlpatterns = [
url(r'^tenants/import/$', views.TenantBulkImportView.as_view(), name='tenant_import'), url(r'^tenants/import/$', views.TenantBulkImportView.as_view(), name='tenant_import'),
url(r'^tenants/edit/$', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'), url(r'^tenants/edit/$', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'),
url(r'^tenants/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'), url(r'^tenants/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'),
url(r'^tenants/(?P<slug>[\w-]+)/$', views.tenant, name='tenant'), url(r'^tenants/(?P<slug>[\w-]+)/$', views.TenantView.as_view(), name='tenant'),
url(r'^tenants/(?P<slug>[\w-]+)/edit/$', views.TenantEditView.as_view(), name='tenant_edit'), url(r'^tenants/(?P<slug>[\w-]+)/edit/$', views.TenantEditView.as_view(), name='tenant_edit'),
url(r'^tenants/(?P<slug>[\w-]+)/delete/$', views.TenantDeleteView.as_view(), name='tenant_delete'), url(r'^tenants/(?P<slug>[\w-]+)/delete/$', views.TenantDeleteView.as_view(), name='tenant_delete'),

View File

@ -2,6 +2,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Count, Q from django.db.models import Count, Q
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.urls import reverse from django.urls import reverse
from django.views.generic import View
from circuits.models import Circuit from circuits.models import Circuit
from dcim.models import Site, Rack, Device from dcim.models import Site, Rack, Device
@ -51,30 +52,32 @@ class TenantListView(ObjectListView):
template_name = 'tenancy/tenant_list.html' template_name = 'tenancy/tenant_list.html'
def tenant(request, slug): class TenantView(View):
tenant = get_object_or_404(Tenant, slug=slug) def get(self, request, slug):
stats = {
'site_count': Site.objects.filter(tenant=tenant).count(),
'rack_count': Rack.objects.filter(tenant=tenant).count(),
'device_count': Device.objects.filter(tenant=tenant).count(),
'vrf_count': VRF.objects.filter(tenant=tenant).count(),
'prefix_count': Prefix.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'ipaddress_count': IPAddress.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'vlan_count': VLAN.objects.filter(tenant=tenant).count(),
'circuit_count': Circuit.objects.filter(tenant=tenant).count(),
}
return render(request, 'tenancy/tenant.html', { tenant = get_object_or_404(Tenant, slug=slug)
'tenant': tenant, stats = {
'stats': stats, 'site_count': Site.objects.filter(tenant=tenant).count(),
}) 'rack_count': Rack.objects.filter(tenant=tenant).count(),
'device_count': Device.objects.filter(tenant=tenant).count(),
'vrf_count': VRF.objects.filter(tenant=tenant).count(),
'prefix_count': Prefix.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'ipaddress_count': IPAddress.objects.filter(
Q(tenant=tenant) |
Q(tenant__isnull=True, vrf__tenant=tenant)
).count(),
'vlan_count': VLAN.objects.filter(tenant=tenant).count(),
'circuit_count': Circuit.objects.filter(tenant=tenant).count(),
}
return render(request, 'tenancy/tenant.html', {
'tenant': tenant,
'stats': stats,
})
class TenantEditView(PermissionRequiredMixin, ObjectEditView): class TenantEditView(PermissionRequiredMixin, ObjectEditView):