From fb85867d72869fdc8963e902bf0e3e932ae00229 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 18 May 2017 17:00:57 -0400 Subject: [PATCH] Converted all object views to class-based views --- netbox/circuits/urls.py | 4 +- netbox/circuits/views.py | 62 ++++--- netbox/dcim/urls.py | 12 +- netbox/dcim/views.py | 373 +++++++++++++++++++++------------------ netbox/ipam/urls.py | 12 +- netbox/ipam/views.py | 349 ++++++++++++++++++++---------------- netbox/secrets/urls.py | 2 +- netbox/secrets/views.py | 15 +- netbox/tenancy/urls.py | 2 +- netbox/tenancy/views.py | 47 ++--- 10 files changed, 487 insertions(+), 391 deletions(-) diff --git a/netbox/circuits/urls.py b/netbox/circuits/urls.py index b23f21a88..be2791382 100644 --- a/netbox/circuits/urls.py +++ b/netbox/circuits/urls.py @@ -12,7 +12,7 @@ urlpatterns = [ 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/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'), - url(r'^providers/(?P[\w-]+)/$', views.provider, name='provider'), + url(r'^providers/(?P[\w-]+)/$', views.ProviderView.as_view(), name='provider'), url(r'^providers/(?P[\w-]+)/edit/$', views.ProviderEditView.as_view(), name='provider_edit'), url(r'^providers/(?P[\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/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'), url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'), - url(r'^circuits/(?P\d+)/$', views.circuit, name='circuit'), + url(r'^circuits/(?P\d+)/$', views.CircuitView.as_view(), name='circuit'), url(r'^circuits/(?P\d+)/edit/$', views.CircuitEditView.as_view(), name='circuit_edit'), url(r'^circuits/(?P\d+)/delete/$', views.CircuitDeleteView.as_view(), name='circuit_delete'), url(r'^circuits/(?P\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'), diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 9cc4dd3c4..d1f192030 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -5,6 +5,7 @@ from django.db import transaction from django.db.models import Count from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse +from django.views.generic import View from extras.models import Graph, GRAPH_TYPE_PROVIDER from utilities.forms import ConfirmationForm @@ -28,18 +29,23 @@ class ProviderListView(ObjectListView): template_name = 'circuits/provider_list.html' -def provider(request, slug): +class ProviderView(View): - provider = get_object_or_404(Provider, slug=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() + def get(self, request, slug): - return render(request, 'circuits/provider.html', { - 'provider': provider, - 'circuits': circuits, - 'show_graphs': show_graphs, - }) + provider = get_object_or_404(Provider, slug=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': provider, + 'circuits': circuits, + 'show_graphs': show_graphs, + }) class ProviderEditView(PermissionRequiredMixin, ObjectEditView): @@ -117,25 +123,27 @@ class CircuitListView(ObjectListView): 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) - 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() + def get(self, request, pk): - return render(request, 'circuits/circuit.html', { - 'circuit': circuit, - 'termination_a': termination_a, - 'termination_z': termination_z, - }) + circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=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': circuit, + 'termination_a': termination_a, + 'termination_z': termination_z, + }) class CircuitEditView(PermissionRequiredMixin, ObjectEditView): diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 8e666f406..bfe74dec6 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -22,7 +22,7 @@ urlpatterns = [ 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/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'), - url(r'^sites/(?P[\w-]+)/$', views.site, name='site'), + url(r'^sites/(?P[\w-]+)/$', views.SiteView.as_view(), name='site'), url(r'^sites/(?P[\w-]+)/edit/$', views.SiteEditView.as_view(), name='site_edit'), url(r'^sites/(?P[\w-]+)/delete/$', views.SiteDeleteView.as_view(), name='site_delete'), url(r'^sites/(?P\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/edit/$', views.RackBulkEditView.as_view(), name='rack_bulk_edit'), url(r'^racks/delete/$', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'), - url(r'^racks/(?P\d+)/$', views.rack, name='rack'), + url(r'^racks/(?P\d+)/$', views.RackView.as_view(), name='rack'), url(r'^racks/(?P\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'), url(r'^racks/(?P\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'), url(r'^racks/(?P\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/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/(?P\d+)/$', views.devicetype, name='devicetype'), + url(r'^device-types/(?P\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'), url(r'^device-types/(?P\d+)/edit/$', views.DeviceTypeEditView.as_view(), name='devicetype_edit'), url(r'^device-types/(?P\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/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'), url(r'^devices/delete/$', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'), - url(r'^devices/(?P\d+)/$', views.device, name='device'), + url(r'^devices/(?P\d+)/$', views.DeviceView.as_view(), name='device'), url(r'^devices/(?P\d+)/edit/$', views.DeviceEditView.as_view(), name='device_edit'), url(r'^devices/(?P\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'), - url(r'^devices/(?P\d+)/inventory/$', views.device_inventory, name='device_inventory'), - url(r'^devices/(?P\d+)/lldp-neighbors/$', views.device_lldp_neighbors, name='device_lldp_neighbors'), + url(r'^devices/(?P\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'), + url(r'^devices/(?P\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'), url(r'^devices/(?P\d+)/add-secret/$', secret_add, name='device_addsecret'), url(r'^devices/(?P\d+)/services/assign/$', ServiceEditView.as_view(), name='service_assign'), url(r'^devices/(?P\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 4ffe2d36b..0e3028e49 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -178,27 +178,29 @@ class SiteListView(ObjectListView): 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) - 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() + def get(self, request, slug): - return render(request, 'dcim/site.html', { - 'site': site, - 'stats': stats, - 'rack_groups': rack_groups, - 'topology_maps': topology_maps, - 'show_graphs': show_graphs, - }) + site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=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': site, + 'stats': stats, + 'rack_groups': rack_groups, + 'topology_maps': topology_maps, + 'show_graphs': show_graphs, + }) class SiteEditView(PermissionRequiredMixin, ObjectEditView): @@ -290,8 +292,13 @@ class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): # class RackListView(ObjectListView): - queryset = Rack.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('devices__device_type')\ - .annotate(device_count=Count('devices', distinct=True)) + queryset = Rack.objects.select_related( + 'site', 'group', 'tenant', 'role' + ).prefetch_related( + 'devices__device_type' + ).annotate( + device_count=Count('devices', distinct=True) + ) filter = filters.RackFilter filter_form = forms.RackFilterForm 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)\ - .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() + rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk) - reservations = RackReservation.objects.filter(rack=rack) - reserved_units = {} - for r in reservations: - for u in r.units: - reserved_units[u] = r + nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True)\ + .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() - return render(request, 'dcim/rack.html', { - 'rack': rack, - '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(), - }) + reservations = RackReservation.objects.filter(rack=rack) + reserved_units = {} + for r in reservations: + for u in r.units: + reserved_units[u] = r + + return render(request, 'dcim/rack.html', { + 'rack': rack, + '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): @@ -481,53 +490,57 @@ class DeviceTypeListView(ObjectListView): 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 - 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 + devicetype = get_object_or_404(DeviceType, pk=pk) - 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, - }) + # Component tables + 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', { + '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): @@ -727,70 +740,114 @@ class DeviceListView(ObjectListView): template_name = 'dcim/device_list.html' -def device(request, pk): +class DeviceView(View): - device = get_object_or_404(Device.objects.select_related( - '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() + def get(self, request, pk): - # Find any related devices for convenient linking in the UI - 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] + device = get_object_or_404(Device.objects.select_related( + '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() - # Show graph button on interfaces only if at least one graph has been created. - show_graphs = Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists() + # Find any related devices for convenient linking in the UI + 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', { - 'device': device, - 'console_ports': console_ports, - 'cs_ports': cs_ports, - 'power_ports': power_ports, - 'power_outlets': power_outlets, - 'interfaces': interfaces, - 'mgmt_interfaces': mgmt_interfaces, - 'device_bays': device_bays, - 'services': services, - 'secrets': secrets, - 'related_devices': related_devices, - 'show_graphs': show_graphs, - }) + # Show graph button on interfaces only if at least one graph has been created. + show_graphs = Graph.objects.filter(type=GRAPH_TYPE_INTERFACE).exists() + + return render(request, 'dcim/device.html', { + 'device': device, + 'console_ports': console_ports, + 'cs_ports': cs_ports, + 'power_ports': power_ports, + 'power_outlets': power_outlets, + 'interfaces': interfaces, + 'mgmt_interfaces': mgmt_interfaces, + 'device_bays': device_bays, + '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): @@ -851,30 +908,6 @@ class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): 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 # diff --git a/netbox/ipam/urls.py b/netbox/ipam/urls.py index a8d7d4528..59b1d1fd3 100644 --- a/netbox/ipam/urls.py +++ b/netbox/ipam/urls.py @@ -12,7 +12,7 @@ urlpatterns = [ 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/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'), - url(r'^vrfs/(?P\d+)/$', views.vrf, name='vrf'), + url(r'^vrfs/(?P\d+)/$', views.VRFView.as_view(), name='vrf'), url(r'^vrfs/(?P\d+)/edit/$', views.VRFEditView.as_view(), name='vrf_edit'), url(r'^vrfs/(?P\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/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'), url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'), - url(r'^aggregates/(?P\d+)/$', views.aggregate, name='aggregate'), + url(r'^aggregates/(?P\d+)/$', views.AggregateView.as_view(), name='aggregate'), url(r'^aggregates/(?P\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'), url(r'^aggregates/(?P\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/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), - url(r'^prefixes/(?P\d+)/$', views.prefix, name='prefix'), + url(r'^prefixes/(?P\d+)/$', views.PrefixView.as_view(), name='prefix'), url(r'^prefixes/(?P\d+)/edit/$', views.PrefixEditView.as_view(), name='prefix_edit'), url(r'^prefixes/(?P\d+)/delete/$', views.PrefixDeleteView.as_view(), name='prefix_delete'), - url(r'^prefixes/(?P\d+)/ip-addresses/$', views.prefix_ipaddresses, name='prefix_ipaddresses'), + url(r'^prefixes/(?P\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'), # IP addresses 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/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/(?P\d+)/$', views.ipaddress, name='ipaddress'), + url(r'^ip-addresses/(?P\d+)/$', views.IPAddressView.as_view(), name='ipaddress'), url(r'^ip-addresses/(?P\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'), url(r'^ip-addresses/(?P\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/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'), url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'), - url(r'^vlans/(?P\d+)/$', views.vlan, name='vlan'), + url(r'^vlans/(?P\d+)/$', views.VLANView.as_view(), name='vlan'), url(r'^vlans/(?P\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'), url(r'^vlans/(?P\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'), diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 82e5f8331..b49db4250 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -6,6 +6,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count, Q from django.shortcuts import get_object_or_404, render from django.urls import reverse +from django.views.generic import View from dcim.models import Device from utilities.paginator import EnhancedPaginator @@ -96,18 +97,20 @@ class VRFListView(ObjectListView): template_name = 'ipam/vrf_list.html' -def vrf(request, pk): +class VRFView(View): - vrf = get_object_or_404(VRF.objects.all(), pk=pk) - prefix_table = tables.PrefixBriefTable( - list(Prefix.objects.filter(vrf=vrf).select_related('site', 'role')) - ) - prefix_table.exclude = ('vrf',) + def get(self, request, pk): - return render(request, 'ipam/vrf.html', { - 'vrf': vrf, - 'prefix_table': prefix_table, - }) + vrf = get_object_or_404(VRF.objects.all(), pk=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': vrf, + 'prefix_table': prefix_table, + }) 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 - 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) + aggregate = get_object_or_404(Aggregate, pk=pk) - prefix_table = tables.PrefixTable(child_prefixes) - if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): - prefix_table.base_columns['pk'].visible = True + # Find all child prefixes contained by this aggregate + 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) - paginate = { - 'klass': EnhancedPaginator, - 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) - } - RequestConfig(request, paginate).configure(prefix_table) + prefix_table = tables.PrefixTable(child_prefixes) + if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): + prefix_table.base_columns['pk'].visible = True - # Compile permissions list for rendering the object table - permissions = { - 'add': request.user.has_perm('ipam.add_prefix'), - 'change': request.user.has_perm('ipam.change_prefix'), - 'delete': request.user.has_perm('ipam.delete_prefix'), - } + paginate = { + 'klass': EnhancedPaginator, + 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) + } + RequestConfig(request, paginate).configure(prefix_table) - return render(request, 'ipam/aggregate.html', { - 'aggregate': aggregate, - 'prefix_table': prefix_table, - 'permissions': permissions, - }) + # Compile permissions list for rendering the object table + permissions = { + 'add': request.user.has_perm('ipam.add_prefix'), + '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): @@ -394,66 +404,120 @@ class PrefixListView(ObjectListView): return self.queryset.annotate_depth(limit=limit) -def prefix(request, pk): +class PrefixView(View): - prefix = get_object_or_404(Prefix.objects.select_related( - 'vrf', 'site__region', 'tenant__group', 'vlan__group', 'role' - ), pk=pk) + def get(self, request, pk): - try: - aggregate = Aggregate.objects.get(prefix__net_contains_or_equals=str(prefix.prefix)) - except Aggregate.DoesNotExist: - aggregate = None + prefix = get_object_or_404(Prefix.objects.select_related( + 'vrf', 'site__region', 'tenant__group', 'vlan__group', 'role' + ), pk=pk) - # Count child IP addresses - ipaddress_count = IPAddress.objects.filter(vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix))\ - .count() + try: + aggregate = Aggregate.objects.get(prefix__net_contains_or_equals=str(prefix.prefix)) + except Aggregate.DoesNotExist: + aggregate = None - # Parent prefixes table - parent_prefixes = Prefix.objects.filter(Q(vrf=prefix.vrf) | Q(vrf__isnull=True))\ - .filter(prefix__net_contains=str(prefix.prefix))\ - .select_related('site', 'role').annotate_depth() - parent_prefix_table = tables.PrefixBriefTable(parent_prefixes) - parent_prefix_table.exclude = ('vrf',) + # Count child IP addresses + ipaddress_count = IPAddress.objects.filter( + vrf=prefix.vrf, address__net_host_contained=str(prefix.prefix) + ).count() - # Duplicate prefixes table - duplicate_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix=str(prefix.prefix)).exclude(pk=prefix.pk)\ - .select_related('site', 'role') - duplicate_prefix_table = tables.PrefixBriefTable(list(duplicate_prefixes)) - duplicate_prefix_table.exclude = ('vrf',) + # Parent prefixes table + parent_prefixes = Prefix.objects.filter( + Q(vrf=prefix.vrf) | Q(vrf__isnull=True) + ).filter( + 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 - child_prefixes = Prefix.objects.filter(vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix))\ - .select_related('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 + # Duplicate prefixes table + duplicate_prefixes = Prefix.objects.filter( + vrf=prefix.vrf, prefix=str(prefix.prefix) + ).exclude( + pk=prefix.pk + ).select_related( + 'site', 'role' + ) + duplicate_prefix_table = tables.PrefixBriefTable(list(duplicate_prefixes)) + duplicate_prefix_table.exclude = ('vrf',) - paginate = { - 'klass': EnhancedPaginator, - 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) - } - RequestConfig(request, paginate).configure(child_prefix_table) + # Child prefixes table + child_prefixes = Prefix.objects.filter( + vrf=prefix.vrf, prefix__net_contained=str(prefix.prefix) + ).select_related( + '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 - permissions = { - 'add': request.user.has_perm('ipam.add_prefix'), - 'change': request.user.has_perm('ipam.change_prefix'), - 'delete': request.user.has_perm('ipam.delete_prefix'), - } + paginate = { + 'klass': EnhancedPaginator, + 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) + } + RequestConfig(request, paginate).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, - 'permissions': permissions, - 'return_url': prefix.get_absolute_url(), - }) + # Compile permissions list for rendering the object table + permissions = { + 'add': request.user.has_perm('ipam.add_prefix'), + 'change': request.user.has_perm('ipam.change_prefix'), + 'delete': request.user.has_perm('ipam.delete_prefix'), + } + + 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, + '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): @@ -495,40 +559,6 @@ class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): 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 # @@ -541,32 +571,47 @@ class IPAddressListView(ObjectListView): 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 - 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',) + ipaddress = get_object_or_404(IPAddress.objects.select_related('interface__device'), pk=pk) - # Duplicate IPs table - duplicate_ips = IPAddress.objects.filter(vrf=ipaddress.vrf, address=str(ipaddress.address))\ - .exclude(pk=ipaddress.pk).select_related('interface__device', 'nat_inside') - duplicate_ips_table = tables.IPAddressBriefTable(list(duplicate_ips)) + # Parent prefixes table + 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',) - # Related IP table - related_ips = IPAddress.objects.select_related('interface__device').exclude(address=str(ipaddress.address))\ - .filter(vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address)) - related_ips_table = tables.IPAddressBriefTable(list(related_ips)) + # Duplicate IPs table + duplicate_ips = IPAddress.objects.filter( + vrf=ipaddress.vrf, address=str(ipaddress.address) + ).exclude( + pk=ipaddress.pk + ).select_related( + 'interface__device', 'nat_inside' + ) + duplicate_ips_table = tables.IPAddressBriefTable(list(duplicate_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, - }) + # Related IP table + related_ips = IPAddress.objects.select_related( + 'interface__device' + ).exclude( + 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): @@ -669,17 +714,21 @@ class VLANListView(ObjectListView): 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) - prefixes = Prefix.objects.filter(vlan=vlan).select_related('vrf', 'site', 'role') - prefix_table = tables.PrefixBriefTable(list(prefixes)) - prefix_table.exclude = ('vlan',) + def get(self, request, pk): - return render(request, 'ipam/vlan.html', { - 'vlan': vlan, - 'prefix_table': prefix_table, - }) + vlan = get_object_or_404(VLAN.objects.select_related( + 'site__region', 'tenant__group', 'role' + ), 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): diff --git a/netbox/secrets/urls.py b/netbox/secrets/urls.py index a4d3b7a78..e801c2de2 100644 --- a/netbox/secrets/urls.py +++ b/netbox/secrets/urls.py @@ -17,7 +17,7 @@ urlpatterns = [ 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/delete/$', views.SecretBulkDeleteView.as_view(), name='secret_bulk_delete'), - url(r'^secrets/(?P\d+)/$', views.secret, name='secret'), + url(r'^secrets/(?P\d+)/$', views.SecretView.as_view(), name='secret'), url(r'^secrets/(?P\d+)/edit/$', views.secret_edit, name='secret_edit'), url(r'^secrets/(?P\d+)/delete/$', views.SecretDeleteView.as_view(), name='secret_delete'), diff --git a/netbox/secrets/views.py b/netbox/secrets/views.py index 0a132dca3..05fb5c262 100644 --- a/netbox/secrets/views.py +++ b/netbox/secrets/views.py @@ -8,6 +8,7 @@ from django.db.models import Count from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.decorators import method_decorator +from django.views.generic import View from dcim.models import Device from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView @@ -65,14 +66,16 @@ class SecretListView(ObjectListView): template_name = 'secrets/secret_list.html' -@login_required -def secret(request, pk): +@method_decorator(login_required, name='dispatch') +class SecretView(View): - secret = get_object_or_404(Secret, pk=pk) + def get(self, request, pk): - return render(request, 'secrets/secret.html', { - 'secret': secret, - }) + secret = get_object_or_404(Secret, pk=pk) + + return render(request, 'secrets/secret.html', { + 'secret': secret, + }) @permission_required('secrets.add_secret') diff --git a/netbox/tenancy/urls.py b/netbox/tenancy/urls.py index b3ca2ecc2..be450be7e 100644 --- a/netbox/tenancy/urls.py +++ b/netbox/tenancy/urls.py @@ -18,7 +18,7 @@ urlpatterns = [ 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/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'), - url(r'^tenants/(?P[\w-]+)/$', views.tenant, name='tenant'), + url(r'^tenants/(?P[\w-]+)/$', views.TenantView.as_view(), name='tenant'), url(r'^tenants/(?P[\w-]+)/edit/$', views.TenantEditView.as_view(), name='tenant_edit'), url(r'^tenants/(?P[\w-]+)/delete/$', views.TenantDeleteView.as_view(), name='tenant_delete'), diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 97ed0eb01..d520039b4 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -2,6 +2,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count, Q from django.shortcuts import get_object_or_404, render from django.urls import reverse +from django.views.generic import View from circuits.models import Circuit from dcim.models import Site, Rack, Device @@ -51,30 +52,32 @@ class TenantListView(ObjectListView): template_name = 'tenancy/tenant_list.html' -def tenant(request, slug): +class TenantView(View): - tenant = get_object_or_404(Tenant, slug=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(), - } + def get(self, request, slug): - return render(request, 'tenancy/tenant.html', { - 'tenant': tenant, - 'stats': stats, - }) + tenant = get_object_or_404(Tenant, slug=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': tenant, + 'stats': stats, + }) class TenantEditView(PermissionRequiredMixin, ObjectEditView):