John Anderson 6 лет назад
Родитель
Сommit
4723ddb5ce

+ 0 - 4
base_requirements.txt

@@ -18,10 +18,6 @@ django-filter
 # https://github.com/django-mptt/django-mptt
 # https://github.com/django-mptt/django-mptt
 django-mptt
 django-mptt
 
 
-# Prometheus metrics client implementation for Django
-# https://github.com/korfuri/django-prometheus
-django-prometheus
-
 # Django caching using Redis
 # Django caching using Redis
 # https://github.com/niwinz/django-redis
 # https://github.com/niwinz/django-redis
 django-redis
 django-redis

+ 10 - 11
netbox/circuits/urls.py

@@ -2,7 +2,6 @@ from django.conf.urls import url
 
 
 from dcim.views import CableCreateView, CableTraceView
 from dcim.views import CableCreateView, CableTraceView
 from extras.views import ObjectChangeLogView
 from extras.views import ObjectChangeLogView
-from utilities.urls import cached
 from . import views
 from . import views
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 
 
@@ -10,41 +9,41 @@ app_name = 'circuits'
 urlpatterns = [
 urlpatterns = [
 
 
     # Providers
     # Providers
-    url(r'^providers/$', cached(views.ProviderListView.as_view()), name='provider_list'),
+    url(r'^providers/$', views.ProviderListView.as_view(), name='provider_list'),
     url(r'^providers/add/$', views.ProviderCreateView.as_view(), name='provider_add'),
     url(r'^providers/add/$', views.ProviderCreateView.as_view(), name='provider_add'),
     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-]+)/$', cached(views.ProviderView.as_view()), 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'),
-    url(r'^providers/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='provider_changelog', kwargs={'model': Provider}),
+    url(r'^providers/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
 
 
     # Circuit types
     # Circuit types
-    url(r'^circuit-types/$', cached(views.CircuitTypeListView.as_view()), name='circuittype_list'),
+    url(r'^circuit-types/$', views.CircuitTypeListView.as_view(), name='circuittype_list'),
     url(r'^circuit-types/add/$', views.CircuitTypeCreateView.as_view(), name='circuittype_add'),
     url(r'^circuit-types/add/$', views.CircuitTypeCreateView.as_view(), name='circuittype_add'),
     url(r'^circuit-types/import/$', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
     url(r'^circuit-types/import/$', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
     url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
     url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
     url(r'^circuit-types/(?P<slug>[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
     url(r'^circuit-types/(?P<slug>[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
-    url(r'^circuit-types/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='circuittype_changelog', kwargs={'model': CircuitType}),
+    url(r'^circuit-types/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
 
 
     # Circuits
     # Circuits
-    url(r'^circuits/$', cached(views.CircuitListView.as_view()), name='circuit_list'),
+    url(r'^circuits/$', views.CircuitListView.as_view(), name='circuit_list'),
     url(r'^circuits/add/$', views.CircuitCreateView.as_view(), name='circuit_add'),
     url(r'^circuits/add/$', views.CircuitCreateView.as_view(), name='circuit_add'),
     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+)/$', cached(views.CircuitView.as_view()), 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+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='circuit_changelog', kwargs={'model': Circuit}),
-    url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', cached(views.circuit_terminations_swap), name='circuit_terminations_swap'),
+    url(r'^circuits/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}),
+    url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'),
 
 
     # Circuit terminations
     # Circuit terminations
     url(r'^circuits/(?P<circuit>\d+)/terminations/add/$', views.CircuitTerminationCreateView.as_view(), name='circuittermination_add'),
     url(r'^circuits/(?P<circuit>\d+)/terminations/add/$', views.CircuitTerminationCreateView.as_view(), name='circuittermination_add'),
     url(r'^circuit-terminations/(?P<pk>\d+)/edit/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
     url(r'^circuit-terminations/(?P<pk>\d+)/edit/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
     url(r'^circuit-terminations/(?P<pk>\d+)/delete/$', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
     url(r'^circuit-terminations/(?P<pk>\d+)/delete/$', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
     url(r'^circuit-terminations/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', CableCreateView.as_view(), name='circuittermination_connect', kwargs={'termination_a_type': CircuitTermination}),
     url(r'^circuit-terminations/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', CableCreateView.as_view(), name='circuittermination_connect', kwargs={'termination_a_type': CircuitTermination}),
-    url(r'^circuit-terminations/(?P<pk>\d+)/trace/$', cached(CableTraceView.as_view()), name='circuittermination_trace', kwargs={'model': CircuitTermination}),
+    url(r'^circuit-terminations/(?P<pk>\d+)/trace/$', CableTraceView.as_view(), name='circuittermination_trace', kwargs={'model': CircuitTermination}),
 
 
 ]
 ]

+ 5 - 0
netbox/circuits/views.py

@@ -1,9 +1,12 @@
+from django.conf import settings
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.decorators import permission_required
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.db import transaction
 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.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 
 
 from extras.models import Graph, GRAPH_TYPE_PROVIDER
 from extras.models import Graph, GRAPH_TYPE_PROVIDER
@@ -32,6 +35,7 @@ class ProviderListView(PermissionRequiredMixin, ObjectListView):
 class ProviderView(PermissionRequiredMixin, View):
 class ProviderView(PermissionRequiredMixin, View):
     permission_required = 'circuits.view_provider'
     permission_required = 'circuits.view_provider'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, slug):
     def get(self, request, slug):
 
 
         provider = get_object_or_404(Provider, slug=slug)
         provider = get_object_or_404(Provider, slug=slug)
@@ -147,6 +151,7 @@ class CircuitListView(PermissionRequiredMixin, ObjectListView):
 class CircuitView(PermissionRequiredMixin, View):
 class CircuitView(PermissionRequiredMixin, View):
     permission_required = 'circuits.view_circuit'
     permission_required = 'circuits.view_circuit'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)
         circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)

+ 101 - 102
netbox/dcim/urls.py

@@ -3,7 +3,6 @@ from django.conf.urls import url
 from extras.views import ObjectChangeLogView, ImageAttachmentEditView
 from extras.views import ObjectChangeLogView, ImageAttachmentEditView
 from ipam.views import ServiceCreateView
 from ipam.views import ServiceCreateView
 from secrets.views import secret_add
 from secrets.views import secret_add
-from utilities.urls import cached
 from . import views
 from . import views
 from .models import (
 from .models import (
     Cable, ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, FrontPort, Interface, Manufacturer, Platform,
     Cable, ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, FrontPort, Interface, Manufacturer, Platform,
@@ -15,291 +14,291 @@ app_name = 'dcim'
 urlpatterns = [
 urlpatterns = [
 
 
     # Regions
     # Regions
-    url(r'^regions/$', cached(views.RegionListView.as_view()), name='region_list'),
-    url(r'^regions/add/$', cached(views.RegionCreateView.as_view()), name='region_add'),
+    url(r'^regions/$', views.RegionListView.as_view(), name='region_list'),
+    url(r'^regions/add/$', views.RegionCreateView.as_view(), name='region_add'),
     url(r'^regions/import/$', views.RegionBulkImportView.as_view(), name='region_import'),
     url(r'^regions/import/$', views.RegionBulkImportView.as_view(), name='region_import'),
     url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
     url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
     url(r'^regions/(?P<pk>\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'),
     url(r'^regions/(?P<pk>\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'),
-    url(r'^regions/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='region_changelog', kwargs={'model': Region}),
+    url(r'^regions/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}),
 
 
     # Sites
     # Sites
-    url(r'^sites/$', cached(views.SiteListView.as_view()), name='site_list'),
-    url(r'^sites/add/$', cached(views.SiteCreateView.as_view()), name='site_add'),
+    url(r'^sites/$', views.SiteListView.as_view(), name='site_list'),
+    url(r'^sites/add/$', views.SiteCreateView.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-]+)/$', cached(views.SiteView.as_view()), 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<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='site_changelog', kwargs={'model': Site}),
-    url(r'^sites/(?P<object_id>\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='site_add_image', kwargs={'model': Site}),
+    url(r'^sites/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
+    url(r'^sites/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}),
 
 
     # Rack groups
     # Rack groups
-    url(r'^rack-groups/$', cached(views.RackGroupListView.as_view()), name='rackgroup_list'),
-    url(r'^rack-groups/add/$', cached(views.RackGroupCreateView.as_view()), name='rackgroup_add'),
+    url(r'^rack-groups/$', views.RackGroupListView.as_view(), name='rackgroup_list'),
+    url(r'^rack-groups/add/$', views.RackGroupCreateView.as_view(), name='rackgroup_add'),
     url(r'^rack-groups/import/$', views.RackGroupBulkImportView.as_view(), name='rackgroup_import'),
     url(r'^rack-groups/import/$', views.RackGroupBulkImportView.as_view(), name='rackgroup_import'),
     url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'),
     url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'),
     url(r'^rack-groups/(?P<pk>\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'),
     url(r'^rack-groups/(?P<pk>\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'),
-    url(r'^rack-groups/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackgroup_changelog', kwargs={'model': RackGroup}),
+    url(r'^rack-groups/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackgroup_changelog', kwargs={'model': RackGroup}),
 
 
     # Rack roles
     # Rack roles
-    url(r'^rack-roles/$', cached(views.RackRoleListView.as_view()), name='rackrole_list'),
-    url(r'^rack-roles/add/$', cached(views.RackRoleCreateView.as_view()), name='rackrole_add'),
+    url(r'^rack-roles/$', views.RackRoleListView.as_view(), name='rackrole_list'),
+    url(r'^rack-roles/add/$', views.RackRoleCreateView.as_view(), name='rackrole_add'),
     url(r'^rack-roles/import/$', views.RackRoleBulkImportView.as_view(), name='rackrole_import'),
     url(r'^rack-roles/import/$', views.RackRoleBulkImportView.as_view(), name='rackrole_import'),
     url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
     url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
     url(r'^rack-roles/(?P<pk>\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'),
     url(r'^rack-roles/(?P<pk>\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'),
-    url(r'^rack-roles/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackrole_changelog', kwargs={'model': RackRole}),
+    url(r'^rack-roles/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackrole_changelog', kwargs={'model': RackRole}),
 
 
     # Rack reservations
     # Rack reservations
-    url(r'^rack-reservations/$', cached(views.RackReservationListView.as_view()), name='rackreservation_list'),
+    url(r'^rack-reservations/$', views.RackReservationListView.as_view(), name='rackreservation_list'),
     url(r'^rack-reservations/edit/$', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'),
     url(r'^rack-reservations/edit/$', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'),
     url(r'^rack-reservations/delete/$', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
     url(r'^rack-reservations/delete/$', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
     url(r'^rack-reservations/(?P<pk>\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'),
     url(r'^rack-reservations/(?P<pk>\d+)/edit/$', views.RackReservationEditView.as_view(), name='rackreservation_edit'),
     url(r'^rack-reservations/(?P<pk>\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'),
     url(r'^rack-reservations/(?P<pk>\d+)/delete/$', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'),
-    url(r'^rack-reservations/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rackreservation_changelog', kwargs={'model': RackReservation}),
+    url(r'^rack-reservations/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rackreservation_changelog', kwargs={'model': RackReservation}),
 
 
     # Racks
     # Racks
-    url(r'^racks/$', cached(views.RackListView.as_view()), name='rack_list'),
-    url(r'^rack-elevations/$', cached(views.RackElevationListView.as_view()), name='rack_elevation_list'),
-    url(r'^racks/add/$', cached(views.RackEditView.as_view()), name='rack_add'),
+    url(r'^racks/$', views.RackListView.as_view(), name='rack_list'),
+    url(r'^rack-elevations/$', views.RackElevationListView.as_view(), name='rack_elevation_list'),
+    url(r'^racks/add/$', views.RackEditView.as_view(), name='rack_add'),
     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+)/$', cached(views.RackView.as_view()), 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<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rack_changelog', kwargs={'model': Rack}),
-    url(r'^racks/(?P<rack>\d+)/reservations/add/$', cached(views.RackReservationCreateView.as_view()), name='rack_add_reservation'),
-    url(r'^racks/(?P<object_id>\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='rack_add_image', kwargs={'model': Rack}),
+    url(r'^racks/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}),
+    url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationCreateView.as_view(), name='rack_add_reservation'),
+    url(r'^racks/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}),
 
 
     # Manufacturers
     # Manufacturers
-    url(r'^manufacturers/$', cached(views.ManufacturerListView.as_view()), name='manufacturer_list'),
-    url(r'^manufacturers/add/$', cached(views.ManufacturerCreateView.as_view()), name='manufacturer_add'),
+    url(r'^manufacturers/$', views.ManufacturerListView.as_view(), name='manufacturer_list'),
+    url(r'^manufacturers/add/$', views.ManufacturerCreateView.as_view(), name='manufacturer_add'),
     url(r'^manufacturers/import/$', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
     url(r'^manufacturers/import/$', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
     url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
     url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
     url(r'^manufacturers/(?P<slug>[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
     url(r'^manufacturers/(?P<slug>[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
-    url(r'^manufacturers/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
+    url(r'^manufacturers/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
 
 
     # Device types
     # Device types
-    url(r'^device-types/$', cached(views.DeviceTypeListView.as_view()), name='devicetype_list'),
-    url(r'^device-types/add/$', cached(views.DeviceTypeCreateView.as_view()), name='devicetype_add'),
+    url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'),
+    url(r'^device-types/add/$', views.DeviceTypeCreateView.as_view(), name='devicetype_add'),
     url(r'^device-types/import/$', views.DeviceTypeBulkImportView.as_view(), name='devicetype_import'),
     url(r'^device-types/import/$', views.DeviceTypeBulkImportView.as_view(), name='devicetype_import'),
     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+)/$', cached(views.DeviceTypeView.as_view()), 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'),
-    url(r'^device-types/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='devicetype_changelog', kwargs={'model': DeviceType}),
+    url(r'^device-types/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='devicetype_changelog', kwargs={'model': DeviceType}),
 
 
     # Console port templates
     # Console port templates
-    url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', cached(views.ConsolePortTemplateCreateView.as_view()), name='devicetype_add_consoleport'),
+    url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortTemplateCreateView.as_view(), name='devicetype_add_consoleport'),
     url(r'^device-types/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'),
     url(r'^device-types/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'),
 
 
     # Console server port templates
     # Console server port templates
-    url(r'^device-types/(?P<pk>\d+)/console-server-ports/add/$', cached(views.ConsoleServerPortTemplateCreateView.as_view()), name='devicetype_add_consoleserverport'),
+    url(r'^device-types/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortTemplateCreateView.as_view(), name='devicetype_add_consoleserverport'),
     url(r'^device-types/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'),
     url(r'^device-types/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'),
 
 
     # Power port templates
     # Power port templates
-    url(r'^device-types/(?P<pk>\d+)/power-ports/add/$', cached(views.PowerPortTemplateCreateView.as_view()), name='devicetype_add_powerport'),
+    url(r'^device-types/(?P<pk>\d+)/power-ports/add/$', views.PowerPortTemplateCreateView.as_view(), name='devicetype_add_powerport'),
     url(r'^device-types/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'),
     url(r'^device-types/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'),
 
 
     # Power outlet templates
     # Power outlet templates
-    url(r'^device-types/(?P<pk>\d+)/power-outlets/add/$', cached(views.PowerOutletTemplateCreateView.as_view()), name='devicetype_add_poweroutlet'),
+    url(r'^device-types/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletTemplateCreateView.as_view(), name='devicetype_add_poweroutlet'),
     url(r'^device-types/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'),
     url(r'^device-types/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'),
 
 
     # Interface templates
     # Interface templates
-    url(r'^device-types/(?P<pk>\d+)/interfaces/add/$', cached(views.InterfaceTemplateCreateView.as_view()), name='devicetype_add_interface'),
+    url(r'^device-types/(?P<pk>\d+)/interfaces/add/$', views.InterfaceTemplateCreateView.as_view(), name='devicetype_add_interface'),
     url(r'^device-types/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'),
     url(r'^device-types/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'),
     url(r'^device-types/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'),
     url(r'^device-types/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'),
 
 
     # Front port templates
     # Front port templates
-    url(r'^device-types/(?P<pk>\d+)/front-ports/add/$', cached(views.FrontPortTemplateCreateView.as_view()), name='devicetype_add_frontport'),
+    url(r'^device-types/(?P<pk>\d+)/front-ports/add/$', views.FrontPortTemplateCreateView.as_view(), name='devicetype_add_frontport'),
     url(r'^device-types/(?P<pk>\d+)/front-ports/delete/$', views.FrontPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_frontport'),
     url(r'^device-types/(?P<pk>\d+)/front-ports/delete/$', views.FrontPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_frontport'),
 
 
     # Rear port templates
     # Rear port templates
-    url(r'^device-types/(?P<pk>\d+)/rear-ports/add/$', cached(views.RearPortTemplateCreateView.as_view()), name='devicetype_add_rearport'),
+    url(r'^device-types/(?P<pk>\d+)/rear-ports/add/$', views.RearPortTemplateCreateView.as_view(), name='devicetype_add_rearport'),
     url(r'^device-types/(?P<pk>\d+)/rear-ports/delete/$', views.RearPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_rearport'),
     url(r'^device-types/(?P<pk>\d+)/rear-ports/delete/$', views.RearPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_rearport'),
 
 
     # Device bay templates
     # Device bay templates
-    url(r'^device-types/(?P<pk>\d+)/device-bays/add/$', cached(views.DeviceBayTemplateCreateView.as_view()), name='devicetype_add_devicebay'),
+    url(r'^device-types/(?P<pk>\d+)/device-bays/add/$', views.DeviceBayTemplateCreateView.as_view(), name='devicetype_add_devicebay'),
     url(r'^device-types/(?P<pk>\d+)/device-bays/delete/$', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'),
     url(r'^device-types/(?P<pk>\d+)/device-bays/delete/$', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'),
 
 
     # Device roles
     # Device roles
-    url(r'^device-roles/$', cached(views.DeviceRoleListView.as_view()), name='devicerole_list'),
-    url(r'^device-roles/add/$', cached(views.DeviceRoleCreateView.as_view()), name='devicerole_add'),
+    url(r'^device-roles/$', views.DeviceRoleListView.as_view(), name='devicerole_list'),
+    url(r'^device-roles/add/$', views.DeviceRoleCreateView.as_view(), name='devicerole_add'),
     url(r'^device-roles/import/$', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
     url(r'^device-roles/import/$', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
     url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
     url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
     url(r'^device-roles/(?P<slug>[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
     url(r'^device-roles/(?P<slug>[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
-    url(r'^device-roles/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='devicerole_changelog', kwargs={'model': DeviceRole}),
+    url(r'^device-roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
 
 
     # Platforms
     # Platforms
-    url(r'^platforms/$', cached(views.PlatformListView.as_view()), name='platform_list'),
-    url(r'^platforms/add/$', cached(views.PlatformCreateView.as_view()), name='platform_add'),
+    url(r'^platforms/$', views.PlatformListView.as_view(), name='platform_list'),
+    url(r'^platforms/add/$', views.PlatformCreateView.as_view(), name='platform_add'),
     url(r'^platforms/import/$', views.PlatformBulkImportView.as_view(), name='platform_import'),
     url(r'^platforms/import/$', views.PlatformBulkImportView.as_view(), name='platform_import'),
     url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
     url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
     url(r'^platforms/(?P<slug>[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'),
     url(r'^platforms/(?P<slug>[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'),
-    url(r'^platforms/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='platform_changelog', kwargs={'model': Platform}),
+    url(r'^platforms/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
 
 
     # Devices
     # Devices
-    url(r'^devices/$', cached(views.DeviceListView.as_view()), name='device_list'),
-    url(r'^devices/add/$', cached(views.DeviceCreateView.as_view()), name='device_add'),
+    url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),
+    url(r'^devices/add/$', views.DeviceCreateView.as_view(), name='device_add'),
     url(r'^devices/import/$', views.DeviceBulkImportView.as_view(), name='device_import'),
     url(r'^devices/import/$', views.DeviceBulkImportView.as_view(), name='device_import'),
     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+)/$', cached(views.DeviceView.as_view()), 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+)/config-context/$', cached(views.DeviceConfigContextView.as_view()), name='device_configcontext'),
-    url(r'^devices/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='device_changelog', kwargs={'model': Device}),
-    url(r'^devices/(?P<pk>\d+)/inventory/$', cached(views.DeviceInventoryView.as_view()), name='device_inventory'),
+    url(r'^devices/(?P<pk>\d+)/config-context/$', views.DeviceConfigContextView.as_view(), name='device_configcontext'),
+    url(r'^devices/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='device_changelog', kwargs={'model': Device}),
+    url(r'^devices/(?P<pk>\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'),
     url(r'^devices/(?P<pk>\d+)/status/$', views.DeviceStatusView.as_view(), name='device_status'),
     url(r'^devices/(?P<pk>\d+)/status/$', views.DeviceStatusView.as_view(), name='device_status'),
     url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), 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+)/config/$', views.DeviceConfigView.as_view(), name='device_config'),
     url(r'^devices/(?P<pk>\d+)/config/$', views.DeviceConfigView.as_view(), name='device_config'),
     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/$', cached(ServiceCreateView.as_view()), name='device_service_assign'),
-    url(r'^devices/(?P<object_id>\d+)/images/add/$', cached(ImageAttachmentEditView.as_view()), name='device_add_image', kwargs={'model': Device}),
+    url(r'^devices/(?P<device>\d+)/services/assign/$', ServiceCreateView.as_view(), name='device_service_assign'),
+    url(r'^devices/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}),
 
 
     # Console ports
     # Console ports
-    url(r'^devices/console-ports/add/$', cached(views.DeviceBulkAddConsolePortView.as_view()), name='device_bulk_add_consoleport'),
-    url(r'^devices/(?P<pk>\d+)/console-ports/add/$', cached(views.ConsolePortCreateView.as_view()), name='consoleport_add'),
+    url(r'^devices/console-ports/add/$', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
+    url(r'^devices/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortCreateView.as_view(), name='consoleport_add'),
     url(r'^devices/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
     url(r'^console-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}),
     url(r'^console-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}),
     url(r'^console-ports/(?P<pk>\d+)/edit/$', views.ConsolePortEditView.as_view(), name='consoleport_edit'),
     url(r'^console-ports/(?P<pk>\d+)/edit/$', views.ConsolePortEditView.as_view(), name='consoleport_edit'),
     url(r'^console-ports/(?P<pk>\d+)/delete/$', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'),
     url(r'^console-ports/(?P<pk>\d+)/delete/$', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'),
-    url(r'^console-ports/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='consoleport_trace', kwargs={'model': ConsolePort}),
+    url(r'^console-ports/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}),
 
 
     # Console server ports
     # Console server ports
-    url(r'^devices/console-server-ports/add/$', cached(views.DeviceBulkAddConsoleServerPortView.as_view()), name='device_bulk_add_consoleserverport'),
-    url(r'^devices/(?P<pk>\d+)/console-server-ports/add/$', cached(views.ConsoleServerPortCreateView.as_view()), name='consoleserverport_add'),
+    url(r'^devices/console-server-ports/add/$', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
+    url(r'^devices/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'),
     url(r'^devices/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
     url(r'^console-server-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}),
     url(r'^console-server-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}),
     url(r'^console-server-ports/(?P<pk>\d+)/edit/$', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'),
     url(r'^console-server-ports/(?P<pk>\d+)/edit/$', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'),
     url(r'^console-server-ports/(?P<pk>\d+)/delete/$', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'),
     url(r'^console-server-ports/(?P<pk>\d+)/delete/$', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'),
-    url(r'^console-server-ports/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}),
-    url(r'^console-server-ports/rename/$', cached(views.ConsoleServerPortBulkRenameView.as_view()), name='consoleserverport_bulk_rename'),
+    url(r'^console-server-ports/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}),
+    url(r'^console-server-ports/rename/$', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
     url(r'^console-server-ports/disconnect/$', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
     url(r'^console-server-ports/disconnect/$', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
 
 
     # Power ports
     # Power ports
-    url(r'^devices/power-ports/add/$', cached(views.DeviceBulkAddPowerPortView.as_view()), name='device_bulk_add_powerport'),
-    url(r'^devices/(?P<pk>\d+)/power-ports/add/$', cached(views.PowerPortCreateView.as_view()), name='powerport_add'),
+    url(r'^devices/power-ports/add/$', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
+    url(r'^devices/(?P<pk>\d+)/power-ports/add/$', views.PowerPortCreateView.as_view(), name='powerport_add'),
     url(r'^devices/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
     url(r'^power-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}),
     url(r'^power-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}),
     url(r'^power-ports/(?P<pk>\d+)/edit/$', views.PowerPortEditView.as_view(), name='powerport_edit'),
     url(r'^power-ports/(?P<pk>\d+)/edit/$', views.PowerPortEditView.as_view(), name='powerport_edit'),
     url(r'^power-ports/(?P<pk>\d+)/delete/$', views.PowerPortDeleteView.as_view(), name='powerport_delete'),
     url(r'^power-ports/(?P<pk>\d+)/delete/$', views.PowerPortDeleteView.as_view(), name='powerport_delete'),
-    url(r'^power-ports/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='powerport_trace', kwargs={'model': PowerPort}),
+    url(r'^power-ports/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}),
 
 
     # Power outlets
     # Power outlets
-    url(r'^devices/power-outlets/add/$', cached(views.DeviceBulkAddPowerOutletView.as_view()), name='device_bulk_add_poweroutlet'),
-    url(r'^devices/(?P<pk>\d+)/power-outlets/add/$', cached(views.PowerOutletCreateView.as_view()), name='poweroutlet_add'),
+    url(r'^devices/power-outlets/add/$', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
+    url(r'^devices/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'),
     url(r'^devices/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
     url(r'^power-outlets/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}),
     url(r'^power-outlets/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}),
     url(r'^power-outlets/(?P<pk>\d+)/edit/$', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'),
     url(r'^power-outlets/(?P<pk>\d+)/edit/$', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'),
     url(r'^power-outlets/(?P<pk>\d+)/delete/$', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'),
     url(r'^power-outlets/(?P<pk>\d+)/delete/$', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'),
-    url(r'^power-outlets/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='poweroutlet_trace', kwargs={'model': PowerOutlet}),
-    url(r'^power-outlets/rename/$', cached(views.PowerOutletBulkRenameView.as_view()), name='poweroutlet_bulk_rename'),
+    url(r'^power-outlets/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}),
+    url(r'^power-outlets/rename/$', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
     url(r'^power-outlets/disconnect/$', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
     url(r'^power-outlets/disconnect/$', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
 
 
     # Interfaces
     # Interfaces
-    url(r'^devices/interfaces/add/$', cached(views.DeviceBulkAddInterfaceView.as_view()), name='device_bulk_add_interface'),
-    url(r'^devices/(?P<pk>\d+)/interfaces/add/$', cached(views.InterfaceCreateView.as_view()), name='interface_add'),
+    url(r'^devices/interfaces/add/$', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
+    url(r'^devices/(?P<pk>\d+)/interfaces/add/$', views.InterfaceCreateView.as_view(), name='interface_add'),
     url(r'^devices/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
     url(r'^interfaces/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}),
     url(r'^interfaces/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}),
-    url(r'^interfaces/(?P<pk>\d+)/$', cached(views.InterfaceView.as_view()), name='interface'),
+    url(r'^interfaces/(?P<pk>\d+)/$', views.InterfaceView.as_view(), name='interface'),
     url(r'^interfaces/(?P<pk>\d+)/edit/$', views.InterfaceEditView.as_view(), name='interface_edit'),
     url(r'^interfaces/(?P<pk>\d+)/edit/$', views.InterfaceEditView.as_view(), name='interface_edit'),
-    url(r'^interfaces/(?P<pk>\d+)/assign-vlans/$', cached(views.InterfaceAssignVLANsView.as_view()), name='interface_assign_vlans'),
+    url(r'^interfaces/(?P<pk>\d+)/assign-vlans/$', views.InterfaceAssignVLANsView.as_view(), name='interface_assign_vlans'),
     url(r'^interfaces/(?P<pk>\d+)/delete/$', views.InterfaceDeleteView.as_view(), name='interface_delete'),
     url(r'^interfaces/(?P<pk>\d+)/delete/$', views.InterfaceDeleteView.as_view(), name='interface_delete'),
-    url(r'^interfaces/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='interface_changelog', kwargs={'model': Interface}),
-    url(r'^interfaces/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='interface_trace', kwargs={'model': Interface}),
-    url(r'^interfaces/rename/$', cached(views.InterfaceBulkRenameView.as_view()), name='interface_bulk_rename'),
+    url(r'^interfaces/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}),
+    url(r'^interfaces/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}),
+    url(r'^interfaces/rename/$', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
     url(r'^interfaces/disconnect/$', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
     url(r'^interfaces/disconnect/$', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
 
 
     # Front ports
     # Front ports
     # url(r'^devices/front-ports/add/$', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
     # url(r'^devices/front-ports/add/$', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
-    url(r'^devices/(?P<pk>\d+)/front-ports/add/$', cached(views.FrontPortCreateView.as_view()), name='frontport_add'),
+    url(r'^devices/(?P<pk>\d+)/front-ports/add/$', views.FrontPortCreateView.as_view(), name='frontport_add'),
     url(r'^devices/(?P<pk>\d+)/front-ports/edit/$', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/front-ports/edit/$', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/front-ports/delete/$', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/front-ports/delete/$', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
     url(r'^front-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}),
     url(r'^front-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}),
     url(r'^front-ports/(?P<pk>\d+)/edit/$', views.FrontPortEditView.as_view(), name='frontport_edit'),
     url(r'^front-ports/(?P<pk>\d+)/edit/$', views.FrontPortEditView.as_view(), name='frontport_edit'),
     url(r'^front-ports/(?P<pk>\d+)/delete/$', views.FrontPortDeleteView.as_view(), name='frontport_delete'),
     url(r'^front-ports/(?P<pk>\d+)/delete/$', views.FrontPortDeleteView.as_view(), name='frontport_delete'),
-    url(r'^front-ports/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='frontport_trace', kwargs={'model': FrontPort}),
-    url(r'^front-ports/rename/$', cached(views.FrontPortBulkRenameView.as_view()), name='frontport_bulk_rename'),
+    url(r'^front-ports/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}),
+    url(r'^front-ports/rename/$', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'),
     url(r'^front-ports/disconnect/$', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
     url(r'^front-ports/disconnect/$', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
 
 
     # Rear ports
     # Rear ports
     # url(r'^devices/rear-ports/add/$', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
     # url(r'^devices/rear-ports/add/$', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
-    url(r'^devices/(?P<pk>\d+)/rear-ports/add/$', cached(views.RearPortCreateView.as_view()), name='rearport_add'),
+    url(r'^devices/(?P<pk>\d+)/rear-ports/add/$', views.RearPortCreateView.as_view(), name='rearport_add'),
     url(r'^devices/(?P<pk>\d+)/rear-ports/edit/$', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/rear-ports/edit/$', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'),
     url(r'^devices/(?P<pk>\d+)/rear-ports/delete/$', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/rear-ports/delete/$', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
     url(r'^rear-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}),
     url(r'^rear-ports/(?P<termination_a_id>\d+)/connect/(?P<termination_b_type>[\w-]+)/$', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}),
     url(r'^rear-ports/(?P<pk>\d+)/edit/$', views.RearPortEditView.as_view(), name='rearport_edit'),
     url(r'^rear-ports/(?P<pk>\d+)/edit/$', views.RearPortEditView.as_view(), name='rearport_edit'),
     url(r'^rear-ports/(?P<pk>\d+)/delete/$', views.RearPortDeleteView.as_view(), name='rearport_delete'),
     url(r'^rear-ports/(?P<pk>\d+)/delete/$', views.RearPortDeleteView.as_view(), name='rearport_delete'),
-    url(r'^rear-ports/(?P<pk>\d+)/trace/$', cached(views.CableTraceView.as_view()), name='rearport_trace', kwargs={'model': RearPort}),
-    url(r'^rear-ports/rename/$', cached(views.RearPortBulkRenameView.as_view()), name='rearport_bulk_rename'),
+    url(r'^rear-ports/(?P<pk>\d+)/trace/$', views.CableTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}),
+    url(r'^rear-ports/rename/$', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'),
     url(r'^rear-ports/disconnect/$', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
     url(r'^rear-ports/disconnect/$', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
 
 
     # Device bays
     # Device bays
-    url(r'^devices/device-bays/add/$', cached(views.DeviceBulkAddDeviceBayView.as_view()), name='device_bulk_add_devicebay'),
-    url(r'^devices/(?P<pk>\d+)/bays/add/$', cached(views.DeviceBayCreateView.as_view()), name='devicebay_add'),
+    url(r'^devices/device-bays/add/$', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
+    url(r'^devices/(?P<pk>\d+)/bays/add/$', views.DeviceBayCreateView.as_view(), name='devicebay_add'),
     url(r'^devices/(?P<pk>\d+)/bays/delete/$', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
     url(r'^devices/(?P<pk>\d+)/bays/delete/$', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
     url(r'^device-bays/(?P<pk>\d+)/edit/$', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
     url(r'^device-bays/(?P<pk>\d+)/edit/$', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
     url(r'^device-bays/(?P<pk>\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
     url(r'^device-bays/(?P<pk>\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
     url(r'^device-bays/(?P<pk>\d+)/populate/$', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'),
     url(r'^device-bays/(?P<pk>\d+)/populate/$', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'),
     url(r'^device-bays/(?P<pk>\d+)/depopulate/$', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'),
     url(r'^device-bays/(?P<pk>\d+)/depopulate/$', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'),
-    url(r'^device-bays/rename/$', cached(views.DeviceBayBulkRenameView.as_view()), name='devicebay_bulk_rename'),
+    url(r'^device-bays/rename/$', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
 
 
     # Inventory items
     # Inventory items
-    url(r'^inventory-items/$', cached(views.InventoryItemListView.as_view()), name='inventoryitem_list'),
+    url(r'^inventory-items/$', views.InventoryItemListView.as_view(), name='inventoryitem_list'),
     url(r'^inventory-items/import/$', views.InventoryItemBulkImportView.as_view(), name='inventoryitem_import'),
     url(r'^inventory-items/import/$', views.InventoryItemBulkImportView.as_view(), name='inventoryitem_import'),
     url(r'^inventory-items/edit/$', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'),
     url(r'^inventory-items/edit/$', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'),
     url(r'^inventory-items/delete/$', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'),
     url(r'^inventory-items/delete/$', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'),
     url(r'^inventory-items/(?P<pk>\d+)/edit/$', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
     url(r'^inventory-items/(?P<pk>\d+)/edit/$', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
     url(r'^inventory-items/(?P<pk>\d+)/delete/$', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
     url(r'^inventory-items/(?P<pk>\d+)/delete/$', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
-    url(r'^devices/(?P<device>\d+)/inventory-items/add/$', cached(views.InventoryItemEditView.as_view()), name='inventoryitem_add'),
+    url(r'^devices/(?P<device>\d+)/inventory-items/add/$', views.InventoryItemEditView.as_view(), name='inventoryitem_add'),
 
 
     # Cables
     # Cables
-    url(r'^cables/$', cached(views.CableListView.as_view()), name='cable_list'),
+    url(r'^cables/$', views.CableListView.as_view(), name='cable_list'),
     url(r'^cables/import/$', views.CableBulkImportView.as_view(), name='cable_import'),
     url(r'^cables/import/$', views.CableBulkImportView.as_view(), name='cable_import'),
     url(r'^cables/edit/$', views.CableBulkEditView.as_view(), name='cable_bulk_edit'),
     url(r'^cables/edit/$', views.CableBulkEditView.as_view(), name='cable_bulk_edit'),
     url(r'^cables/delete/$', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'),
     url(r'^cables/delete/$', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'),
-    url(r'^cables/(?P<pk>\d+)/$', cached(views.CableView.as_view()), name='cable'),
+    url(r'^cables/(?P<pk>\d+)/$', views.CableView.as_view(), name='cable'),
     url(r'^cables/(?P<pk>\d+)/edit/$', views.CableEditView.as_view(), name='cable_edit'),
     url(r'^cables/(?P<pk>\d+)/edit/$', views.CableEditView.as_view(), name='cable_edit'),
     url(r'^cables/(?P<pk>\d+)/delete/$', views.CableDeleteView.as_view(), name='cable_delete'),
     url(r'^cables/(?P<pk>\d+)/delete/$', views.CableDeleteView.as_view(), name='cable_delete'),
-    url(r'^cables/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='cable_changelog', kwargs={'model': Cable}),
+    url(r'^cables/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='cable_changelog', kwargs={'model': Cable}),
 
 
     # Console/power/interface connections (read-only)
     # Console/power/interface connections (read-only)
-    url(r'^console-connections/$', cached(views.ConsoleConnectionsListView.as_view()), name='console_connections_list'),
-    url(r'^power-connections/$', cached(views.PowerConnectionsListView.as_view()), name='power_connections_list'),
-    url(r'^interface-connections/$', cached(views.InterfaceConnectionsListView.as_view()), name='interface_connections_list'),
+    url(r'^console-connections/$', views.ConsoleConnectionsListView.as_view(), name='console_connections_list'),
+    url(r'^power-connections/$', views.PowerConnectionsListView.as_view(), name='power_connections_list'),
+    url(r'^interface-connections/$', views.InterfaceConnectionsListView.as_view(), name='interface_connections_list'),
 
 
     # Virtual chassis
     # Virtual chassis
-    url(r'^virtual-chassis/$', cached(views.VirtualChassisListView.as_view()), name='virtualchassis_list'),
-    url(r'^virtual-chassis/add/$', cached(views.VirtualChassisCreateView.as_view()), name='virtualchassis_add'),
+    url(r'^virtual-chassis/$', views.VirtualChassisListView.as_view(), name='virtualchassis_list'),
+    url(r'^virtual-chassis/add/$', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'),
     url(r'^virtual-chassis/(?P<pk>\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
     url(r'^virtual-chassis/(?P<pk>\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
     url(r'^virtual-chassis/(?P<pk>\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
     url(r'^virtual-chassis/(?P<pk>\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
-    url(r'^virtual-chassis/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}),
+    url(r'^virtual-chassis/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}),
     url(r'^virtual-chassis/(?P<pk>\d+)/add-member/$', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'),
     url(r'^virtual-chassis/(?P<pk>\d+)/add-member/$', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'),
     url(r'^virtual-chassis-members/(?P<pk>\d+)/delete/$', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'),
     url(r'^virtual-chassis-members/(?P<pk>\d+)/delete/$', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'),
 
 
     # Power panels
     # Power panels
-    url(r'^power-panels/$', cached(views.PowerPanelListView.as_view()), name='powerpanel_list'),
-    url(r'^power-panels/add/$', cached(views.PowerPanelCreateView.as_view()), name='powerpanel_add'),
+    url(r'^power-panels/$', views.PowerPanelListView.as_view(), name='powerpanel_list'),
+    url(r'^power-panels/add/$', views.PowerPanelCreateView.as_view(), name='powerpanel_add'),
     url(r'^power-panels/import/$', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'),
     url(r'^power-panels/import/$', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'),
     url(r'^power-panels/delete/$', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'),
     url(r'^power-panels/delete/$', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'),
-    url(r'^power-panels/(?P<pk>\d+)/$', cached(views.PowerPanelView.as_view()), name='powerpanel'),
+    url(r'^power-panels/(?P<pk>\d+)/$', views.PowerPanelView.as_view(), name='powerpanel'),
     url(r'^power-panels/(?P<pk>\d+)/edit/$', views.PowerPanelEditView.as_view(), name='powerpanel_edit'),
     url(r'^power-panels/(?P<pk>\d+)/edit/$', views.PowerPanelEditView.as_view(), name='powerpanel_edit'),
     url(r'^power-panels/(?P<pk>\d+)/delete/$', views.PowerPanelDeleteView.as_view(), name='powerpanel_delete'),
     url(r'^power-panels/(?P<pk>\d+)/delete/$', views.PowerPanelDeleteView.as_view(), name='powerpanel_delete'),
-    url(r'^power-panels/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='powerpanel_changelog', kwargs={'model': PowerPanel}),
+    url(r'^power-panels/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='powerpanel_changelog', kwargs={'model': PowerPanel}),
 
 
     # Power feeds
     # Power feeds
-    url(r'^power-feeds/$', cached(views.PowerFeedListView.as_view()), name='powerfeed_list'),
-    url(r'^power-feeds/add/$', cached(views.PowerFeedEditView.as_view()), name='powerfeed_add'),
+    url(r'^power-feeds/$', views.PowerFeedListView.as_view(), name='powerfeed_list'),
+    url(r'^power-feeds/add/$', views.PowerFeedEditView.as_view(), name='powerfeed_add'),
     url(r'^power-feeds/import/$', views.PowerFeedBulkImportView.as_view(), name='powerfeed_import'),
     url(r'^power-feeds/import/$', views.PowerFeedBulkImportView.as_view(), name='powerfeed_import'),
     url(r'^power-feeds/edit/$', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'),
     url(r'^power-feeds/edit/$', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'),
     url(r'^power-feeds/delete/$', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'),
     url(r'^power-feeds/delete/$', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'),
-    url(r'^power-feeds/(?P<pk>\d+)/$', cached(views.PowerFeedView.as_view()), name='powerfeed'),
+    url(r'^power-feeds/(?P<pk>\d+)/$', views.PowerFeedView.as_view(), name='powerfeed'),
     url(r'^power-feeds/(?P<pk>\d+)/edit/$', views.PowerFeedEditView.as_view(), name='powerfeed_edit'),
     url(r'^power-feeds/(?P<pk>\d+)/edit/$', views.PowerFeedEditView.as_view(), name='powerfeed_edit'),
     url(r'^power-feeds/(?P<pk>\d+)/delete/$', views.PowerFeedDeleteView.as_view(), name='powerfeed_delete'),
     url(r'^power-feeds/(?P<pk>\d+)/delete/$', views.PowerFeedDeleteView.as_view(), name='powerfeed_delete'),
-    url(r'^power-feeds/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='powerfeed_changelog', kwargs={'model': PowerFeed}),
+    url(r'^power-feeds/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='powerfeed_changelog', kwargs={'model': PowerFeed}),
 
 
 ]
 ]

+ 22 - 0
netbox/dcim/views.py

@@ -13,6 +13,8 @@ from django.urls import reverse
 from django.utils.html import escape
 from django.utils.html import escape
 from django.utils.http import is_safe_url
 from django.utils.http import is_safe_url
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 
 
 from circuits.models import Circuit
 from circuits.models import Circuit
@@ -195,6 +197,7 @@ class SiteListView(PermissionRequiredMixin, ObjectListView):
 class SiteView(PermissionRequiredMixin, View):
 class SiteView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_site'
     permission_required = 'dcim.view_site'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, slug):
     def get(self, request, slug):
 
 
         site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=slug)
         site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=slug)
@@ -353,6 +356,7 @@ class RackElevationListView(PermissionRequiredMixin, View):
     """
     """
     permission_required = 'dcim.view_rack'
     permission_required = 'dcim.view_rack'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         racks = Rack.objects.select_related(
         racks = Rack.objects.select_related(
@@ -392,6 +396,7 @@ class RackElevationListView(PermissionRequiredMixin, View):
 class RackView(PermissionRequiredMixin, View):
 class RackView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_rack'
     permission_required = 'dcim.view_rack'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
         rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
@@ -570,6 +575,7 @@ class DeviceTypeListView(PermissionRequiredMixin, ObjectListView):
 class DeviceTypeView(PermissionRequiredMixin, View):
 class DeviceTypeView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_devicetype'
     permission_required = 'dcim.view_devicetype'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         devicetype = get_object_or_404(DeviceType, pk=pk)
         devicetype = get_object_or_404(DeviceType, pk=pk)
@@ -910,6 +916,7 @@ class DeviceListView(PermissionRequiredMixin, ObjectListView):
 class DeviceView(PermissionRequiredMixin, View):
 class DeviceView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_device'
     permission_required = 'dcim.view_device'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device.objects.select_related(
         device = get_object_or_404(Device.objects.select_related(
@@ -991,6 +998,7 @@ class DeviceView(PermissionRequiredMixin, View):
 class DeviceInventoryView(PermissionRequiredMixin, View):
 class DeviceInventoryView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_device'
     permission_required = 'dcim.view_device'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device, pk=pk)
         device = get_object_or_404(Device, pk=pk)
@@ -1012,6 +1020,7 @@ class DeviceInventoryView(PermissionRequiredMixin, View):
 class DeviceStatusView(PermissionRequiredMixin, View):
 class DeviceStatusView(PermissionRequiredMixin, View):
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device, pk=pk)
         device = get_object_or_404(Device, pk=pk)
@@ -1025,6 +1034,7 @@ class DeviceStatusView(PermissionRequiredMixin, View):
 class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
 class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device, pk=pk)
         device = get_object_or_404(Device, pk=pk)
@@ -1042,6 +1052,7 @@ class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
 class DeviceConfigView(PermissionRequiredMixin, View):
 class DeviceConfigView(PermissionRequiredMixin, View):
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
     permission_required = ('dcim.view_device', 'dcim.napalm_read')
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device, pk=pk)
         device = get_object_or_404(Device, pk=pk)
@@ -1279,6 +1290,7 @@ class PowerOutletBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 class InterfaceView(PermissionRequiredMixin, View):
 class InterfaceView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_interface'
     permission_required = 'dcim.view_interface'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         interface = get_object_or_404(Interface, pk=pk)
         interface = get_object_or_404(Interface, pk=pk)
@@ -1499,6 +1511,7 @@ class DeviceBayDeleteView(PermissionRequiredMixin, ObjectDeleteView):
 class DeviceBayPopulateView(PermissionRequiredMixin, View):
 class DeviceBayPopulateView(PermissionRequiredMixin, View):
     permission_required = 'dcim.change_devicebay'
     permission_required = 'dcim.change_devicebay'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device_bay = get_object_or_404(DeviceBay, pk=pk)
         device_bay = get_object_or_404(DeviceBay, pk=pk)
@@ -1533,6 +1546,7 @@ class DeviceBayPopulateView(PermissionRequiredMixin, View):
 class DeviceBayDepopulateView(PermissionRequiredMixin, View):
 class DeviceBayDepopulateView(PermissionRequiredMixin, View):
     permission_required = 'dcim.change_devicebay'
     permission_required = 'dcim.change_devicebay'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device_bay = get_object_or_404(DeviceBay, pk=pk)
         device_bay = get_object_or_404(DeviceBay, pk=pk)
@@ -1672,6 +1686,7 @@ class CableListView(PermissionRequiredMixin, ObjectListView):
 class CableView(PermissionRequiredMixin, View):
 class CableView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_cable'
     permission_required = 'dcim.view_cable'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         cable = get_object_or_404(Cable, pk=pk)
         cable = get_object_or_404(Cable, pk=pk)
@@ -1687,6 +1702,7 @@ class CableTraceView(PermissionRequiredMixin, View):
     """
     """
     permission_required = 'dcim.view_cable'
     permission_required = 'dcim.view_cable'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, model, pk):
     def get(self, request, model, pk):
 
 
         obj = get_object_or_404(model, pk=pk)
         obj = get_object_or_404(model, pk=pk)
@@ -1726,6 +1742,7 @@ class CableCreateView(PermissionRequiredMixin, GetReturnURLMixin, View):
 
 
         return super().dispatch(request, *args, **kwargs)
         return super().dispatch(request, *args, **kwargs)
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, *args, **kwargs):
     def get(self, request, *args, **kwargs):
 
 
         # Parse initial data manually to avoid setting field values as lists
         # Parse initial data manually to avoid setting field values as lists
@@ -2042,6 +2059,7 @@ class VirtualChassisCreateView(PermissionRequiredMixin, View):
 class VirtualChassisEditView(PermissionRequiredMixin, GetReturnURLMixin, View):
 class VirtualChassisEditView(PermissionRequiredMixin, GetReturnURLMixin, View):
     permission_required = 'dcim.change_virtualchassis'
     permission_required = 'dcim.change_virtualchassis'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
         virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
@@ -2110,6 +2128,7 @@ class VirtualChassisDeleteView(PermissionRequiredMixin, ObjectDeleteView):
 class VirtualChassisAddMemberView(PermissionRequiredMixin, GetReturnURLMixin, View):
 class VirtualChassisAddMemberView(PermissionRequiredMixin, GetReturnURLMixin, View):
     permission_required = 'dcim.change_virtualchassis'
     permission_required = 'dcim.change_virtualchassis'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
         virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
@@ -2164,6 +2183,7 @@ class VirtualChassisAddMemberView(PermissionRequiredMixin, GetReturnURLMixin, Vi
 class VirtualChassisRemoveMemberView(PermissionRequiredMixin, GetReturnURLMixin, View):
 class VirtualChassisRemoveMemberView(PermissionRequiredMixin, GetReturnURLMixin, View):
     permission_required = 'dcim.change_virtualchassis'
     permission_required = 'dcim.change_virtualchassis'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         device = get_object_or_404(Device, pk=pk, virtual_chassis__isnull=False)
         device = get_object_or_404(Device, pk=pk, virtual_chassis__isnull=False)
@@ -2227,6 +2247,7 @@ class PowerPanelListView(PermissionRequiredMixin, ObjectListView):
 class PowerPanelView(PermissionRequiredMixin, View):
 class PowerPanelView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_powerpanel'
     permission_required = 'dcim.view_powerpanel'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         powerpanel = get_object_or_404(PowerPanel.objects.select_related('site', 'rack_group'), pk=pk)
         powerpanel = get_object_or_404(PowerPanel.objects.select_related('site', 'rack_group'), pk=pk)
@@ -2296,6 +2317,7 @@ class PowerFeedListView(PermissionRequiredMixin, ObjectListView):
 class PowerFeedView(PermissionRequiredMixin, View):
 class PowerFeedView(PermissionRequiredMixin, View):
     permission_required = 'dcim.view_powerfeed'
     permission_required = 'dcim.view_powerfeed'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         powerfeed = get_object_or_404(PowerFeed.objects.select_related('power_panel', 'rack'), pk=pk)
         powerfeed = get_object_or_404(PowerFeed.objects.select_related('power_panel', 'rack'), pk=pk)

+ 10 - 11
netbox/extras/urls.py

@@ -2,26 +2,25 @@ from django.conf.urls import url
 
 
 from extras import views
 from extras import views
 from extras.models import Tag
 from extras.models import Tag
-from utilities.urls import cached
 
 
 
 
 app_name = 'extras'
 app_name = 'extras'
 urlpatterns = [
 urlpatterns = [
 
 
     # Tags
     # Tags
-    url(r'^tags/$', cached(views.TagListView.as_view()), name='tag_list'),
+    url(r'^tags/$', views.TagListView.as_view(), name='tag_list'),
     url(r'^tags/delete/$', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),
     url(r'^tags/delete/$', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),
-    url(r'^tags/(?P<slug>[\w-]+)/$', cached(views.TagView.as_view()), name='tag'),
+    url(r'^tags/(?P<slug>[\w-]+)/$', views.TagView.as_view(), name='tag'),
     url(r'^tags/(?P<slug>[\w-]+)/edit/$', views.TagEditView.as_view(), name='tag_edit'),
     url(r'^tags/(?P<slug>[\w-]+)/edit/$', views.TagEditView.as_view(), name='tag_edit'),
     url(r'^tags/(?P<slug>[\w-]+)/delete/$', views.TagDeleteView.as_view(), name='tag_delete'),
     url(r'^tags/(?P<slug>[\w-]+)/delete/$', views.TagDeleteView.as_view(), name='tag_delete'),
-    url(r'^tags/(?P<slug>[\w-]+)/changelog/$', cached(views.ObjectChangeLogView.as_view()), name='tag_changelog', kwargs={'model': Tag}),
+    url(r'^tags/(?P<slug>[\w-]+)/changelog/$', views.ObjectChangeLogView.as_view(), name='tag_changelog', kwargs={'model': Tag}),
 
 
     # Config contexts
     # Config contexts
-    url(r'^config-contexts/$', cached(views.ConfigContextListView.as_view()), name='configcontext_list'),
-    url(r'^config-contexts/add/$', cached(views.ConfigContextCreateView.as_view()), name='configcontext_add'),
+    url(r'^config-contexts/$', views.ConfigContextListView.as_view(), name='configcontext_list'),
+    url(r'^config-contexts/add/$', views.ConfigContextCreateView.as_view(), name='configcontext_add'),
     url(r'^config-contexts/edit/$', views.ConfigContextBulkEditView.as_view(), name='configcontext_bulk_edit'),
     url(r'^config-contexts/edit/$', views.ConfigContextBulkEditView.as_view(), name='configcontext_bulk_edit'),
     url(r'^config-contexts/delete/$', views.ConfigContextBulkDeleteView.as_view(), name='configcontext_bulk_delete'),
     url(r'^config-contexts/delete/$', views.ConfigContextBulkDeleteView.as_view(), name='configcontext_bulk_delete'),
-    url(r'^config-contexts/(?P<pk>\d+)/$', cached(views.ConfigContextView.as_view()), name='configcontext'),
+    url(r'^config-contexts/(?P<pk>\d+)/$', views.ConfigContextView.as_view(), name='configcontext'),
     url(r'^config-contexts/(?P<pk>\d+)/edit/$', views.ConfigContextEditView.as_view(), name='configcontext_edit'),
     url(r'^config-contexts/(?P<pk>\d+)/edit/$', views.ConfigContextEditView.as_view(), name='configcontext_edit'),
     url(r'^config-contexts/(?P<pk>\d+)/delete/$', views.ConfigContextDeleteView.as_view(), name='configcontext_delete'),
     url(r'^config-contexts/(?P<pk>\d+)/delete/$', views.ConfigContextDeleteView.as_view(), name='configcontext_delete'),
 
 
@@ -30,12 +29,12 @@ urlpatterns = [
     url(r'^image-attachments/(?P<pk>\d+)/delete/$', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'),
     url(r'^image-attachments/(?P<pk>\d+)/delete/$', views.ImageAttachmentDeleteView.as_view(), name='imageattachment_delete'),
 
 
     # Reports
     # Reports
-    url(r'^reports/$', cached(views.ReportListView.as_view()), name='report_list'),
-    url(r'^reports/(?P<name>[^/]+\.[^/]+)/$', cached(views.ReportView.as_view()), name='report'),
+    url(r'^reports/$', views.ReportListView.as_view(), name='report_list'),
+    url(r'^reports/(?P<name>[^/]+\.[^/]+)/$', views.ReportView.as_view(), name='report'),
     url(r'^reports/(?P<name>[^/]+\.[^/]+)/run/$', views.ReportRunView.as_view(), name='report_run'),
     url(r'^reports/(?P<name>[^/]+\.[^/]+)/run/$', views.ReportRunView.as_view(), name='report_run'),
 
 
     # Change logging
     # Change logging
-    url(r'^changelog/$', cached(views.ObjectChangeListView.as_view()), name='objectchange_list'),
-    url(r'^changelog/(?P<pk>\d+)/$', cached(views.ObjectChangeView.as_view()), name='objectchange'),
+    url(r'^changelog/$', views.ObjectChangeListView.as_view(), name='objectchange_list'),
+    url(r'^changelog/(?P<pk>\d+)/$', views.ObjectChangeView.as_view(), name='objectchange'),
 
 
 ]
 ]

+ 9 - 0
netbox/extras/views.py

@@ -7,6 +7,8 @@ from django.db.models import Count, Q
 from django.http import Http404
 from django.http import Http404
 from django.shortcuts import get_object_or_404, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 from django_tables2 import RequestConfig
 from django_tables2 import RequestConfig
 
 
@@ -41,6 +43,7 @@ class TagListView(ObjectListView):
 
 
 class TagView(View):
 class TagView(View):
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, slug):
     def get(self, request, slug):
 
 
         tag = get_object_or_404(Tag, slug=slug)
         tag = get_object_or_404(Tag, slug=slug)
@@ -108,6 +111,7 @@ class ConfigContextListView(PermissionRequiredMixin, ObjectListView):
 class ConfigContextView(PermissionRequiredMixin, View):
 class ConfigContextView(PermissionRequiredMixin, View):
     permission_required = 'extras.view_configcontext'
     permission_required = 'extras.view_configcontext'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         configcontext = get_object_or_404(ConfigContext, pk=pk)
         configcontext = get_object_or_404(ConfigContext, pk=pk)
@@ -155,6 +159,7 @@ class ObjectConfigContextView(View):
     object_class = None
     object_class = None
     base_template = None
     base_template = None
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         obj = get_object_or_404(self.object_class, pk=pk)
         obj = get_object_or_404(self.object_class, pk=pk)
@@ -187,6 +192,7 @@ class ObjectChangeListView(PermissionRequiredMixin, ObjectListView):
 class ObjectChangeView(PermissionRequiredMixin, View):
 class ObjectChangeView(PermissionRequiredMixin, View):
     permission_required = 'extras.view_objectchange'
     permission_required = 'extras.view_objectchange'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         objectchange = get_object_or_404(ObjectChange, pk=pk)
         objectchange = get_object_or_404(ObjectChange, pk=pk)
@@ -209,6 +215,7 @@ class ObjectChangeLogView(View):
     Present a history of changes made to a particular object.
     Present a history of changes made to a particular object.
     """
     """
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, model, **kwargs):
     def get(self, request, model, **kwargs):
 
 
         # Get object my model and kwargs (e.g. slug='foo')
         # Get object my model and kwargs (e.g. slug='foo')
@@ -282,6 +289,7 @@ class ReportListView(PermissionRequiredMixin, View):
     """
     """
     permission_required = 'extras.view_reportresult'
     permission_required = 'extras.view_reportresult'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         reports = get_reports()
         reports = get_reports()
@@ -306,6 +314,7 @@ class ReportView(PermissionRequiredMixin, View):
     """
     """
     permission_required = 'extras.view_reportresult'
     permission_required = 'extras.view_reportresult'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, name):
     def get(self, request, name):
 
 
         # Retrieve the Report by "<module>.<report>"
         # Retrieve the Report by "<module>.<report>"

+ 37 - 38
netbox/ipam/urls.py

@@ -1,7 +1,6 @@
 from django.conf.urls import url
 from django.conf.urls import url
 
 
 from extras.views import ObjectChangeLogView
 from extras.views import ObjectChangeLogView
-from utilities.urls import cached
 from . import views
 from . import views
 from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
 
 
@@ -9,97 +8,97 @@ app_name = 'ipam'
 urlpatterns = [
 urlpatterns = [
 
 
     # VRFs
     # VRFs
-    url(r'^vrfs/$', cached(views.VRFListView.as_view()), name='vrf_list'),
-    url(r'^vrfs/add/$', cached(views.VRFCreateView.as_view()), name='vrf_add'),
+    url(r'^vrfs/$', views.VRFListView.as_view(), name='vrf_list'),
+    url(r'^vrfs/add/$', views.VRFCreateView.as_view(), name='vrf_add'),
     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+)/$', cached(views.VRFView.as_view()), 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'),
-    url(r'^vrfs/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vrf_changelog', kwargs={'model': VRF}),
+    url(r'^vrfs/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vrf_changelog', kwargs={'model': VRF}),
 
 
     # RIRs
     # RIRs
-    url(r'^rirs/$', cached(views.RIRListView.as_view()), name='rir_list'),
-    url(r'^rirs/add/$', cached(views.RIRCreateView.as_view()), name='rir_add'),
+    url(r'^rirs/$', views.RIRListView.as_view(), name='rir_list'),
+    url(r'^rirs/add/$', views.RIRCreateView.as_view(), name='rir_add'),
     url(r'^rirs/import/$', views.RIRBulkImportView.as_view(), name='rir_import'),
     url(r'^rirs/import/$', views.RIRBulkImportView.as_view(), name='rir_import'),
     url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
     url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
     url(r'^rirs/(?P<slug>[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'),
     url(r'^rirs/(?P<slug>[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'),
-    url(r'^vrfs/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='rir_changelog', kwargs={'model': RIR}),
+    url(r'^vrfs/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}),
 
 
     # Aggregates
     # Aggregates
-    url(r'^aggregates/$', cached(views.AggregateListView.as_view()), name='aggregate_list'),
-    url(r'^aggregates/add/$', cached(views.AggregateCreateView.as_view()), name='aggregate_add'),
+    url(r'^aggregates/$', views.AggregateListView.as_view(), name='aggregate_list'),
+    url(r'^aggregates/add/$', views.AggregateCreateView.as_view(), name='aggregate_add'),
     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+)/$', cached(views.AggregateView.as_view()), 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'),
-    url(r'^aggregates/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='aggregate_changelog', kwargs={'model': Aggregate}),
+    url(r'^aggregates/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='aggregate_changelog', kwargs={'model': Aggregate}),
 
 
     # Roles
     # Roles
-    url(r'^roles/$', cached(views.RoleListView.as_view()), name='role_list'),
-    url(r'^roles/add/$', cached(views.RoleCreateView.as_view()), name='role_add'),
+    url(r'^roles/$', views.RoleListView.as_view(), name='role_list'),
+    url(r'^roles/add/$', views.RoleCreateView.as_view(), name='role_add'),
     url(r'^roles/import/$', views.RoleBulkImportView.as_view(), name='role_import'),
     url(r'^roles/import/$', views.RoleBulkImportView.as_view(), name='role_import'),
     url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
     url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
     url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
     url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
-    url(r'^roles/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='role_changelog', kwargs={'model': Role}),
+    url(r'^roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}),
 
 
     # Prefixes
     # Prefixes
-    url(r'^prefixes/$', cached(views.PrefixListView.as_view()), name='prefix_list'),
-    url(r'^prefixes/add/$', cached(views.PrefixCreateView.as_view()), name='prefix_add'),
+    url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'),
+    url(r'^prefixes/add/$', views.PrefixCreateView.as_view(), name='prefix_add'),
     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+)/$', cached(views.PrefixView.as_view()), 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+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='prefix_changelog', kwargs={'model': Prefix}),
-    url(r'^prefixes/(?P<pk>\d+)/prefixes/$', cached(views.PrefixPrefixesView.as_view()), name='prefix_prefixes'),
-    url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', cached(views.PrefixIPAddressesView.as_view()), name='prefix_ipaddresses'),
+    url(r'^prefixes/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='prefix_changelog', kwargs={'model': Prefix}),
+    url(r'^prefixes/(?P<pk>\d+)/prefixes/$', views.PrefixPrefixesView.as_view(), name='prefix_prefixes'),
+    url(r'^prefixes/(?P<pk>\d+)/ip-addresses/$', views.PrefixIPAddressesView.as_view(), name='prefix_ipaddresses'),
 
 
     # IP addresses
     # IP addresses
-    url(r'^ip-addresses/$', cached(views.IPAddressListView.as_view()), name='ipaddress_list'),
-    url(r'^ip-addresses/add/$', cached(views.IPAddressCreateView.as_view()), name='ipaddress_add'),
-    url(r'^ip-addresses/bulk-add/$', cached(views.IPAddressBulkCreateView.as_view()), name='ipaddress_bulk_add'),
+    url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'),
+    url(r'^ip-addresses/add/$', views.IPAddressCreateView.as_view(), name='ipaddress_add'),
+    url(r'^ip-addresses/bulk-add/$', views.IPAddressBulkCreateView.as_view(), name='ipaddress_bulk_add'),
     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+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='ipaddress_changelog', kwargs={'model': IPAddress}),
+    url(r'^ip-addresses/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='ipaddress_changelog', kwargs={'model': IPAddress}),
     url(r'^ip-addresses/assign/$', views.IPAddressAssignView.as_view(), name='ipaddress_assign'),
     url(r'^ip-addresses/assign/$', views.IPAddressAssignView.as_view(), name='ipaddress_assign'),
-    url(r'^ip-addresses/(?P<pk>\d+)/$', cached(views.IPAddressView.as_view()), 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'),
 
 
     # VLAN groups
     # VLAN groups
-    url(r'^vlan-groups/$', cached(views.VLANGroupListView.as_view()), name='vlangroup_list'),
-    url(r'^vlan-groups/add/$', cached(views.VLANGroupCreateView.as_view()), name='vlangroup_add'),
+    url(r'^vlan-groups/$', views.VLANGroupListView.as_view(), name='vlangroup_list'),
+    url(r'^vlan-groups/add/$', views.VLANGroupCreateView.as_view(), name='vlangroup_add'),
     url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'),
     url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'),
     url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
     url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
     url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
     url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
-    url(r'^vlan-groups/(?P<pk>\d+)/vlans/$', cached(views.VLANGroupVLANsView.as_view()), name='vlangroup_vlans'),
-    url(r'^vlan-groups/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vlangroup_changelog', kwargs={'model': VLANGroup}),
+    url(r'^vlan-groups/(?P<pk>\d+)/vlans/$', views.VLANGroupVLANsView.as_view(), name='vlangroup_vlans'),
+    url(r'^vlan-groups/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlangroup_changelog', kwargs={'model': VLANGroup}),
 
 
     # VLANs
     # VLANs
-    url(r'^vlans/$', cached(views.VLANListView.as_view()), name='vlan_list'),
-    url(r'^vlans/add/$', cached(views.VLANCreateView.as_view()), name='vlan_add'),
+    url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'),
+    url(r'^vlans/add/$', views.VLANCreateView.as_view(), name='vlan_add'),
     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+)/$', cached(views.VLANView.as_view()), name='vlan'),
-    url(r'^vlans/(?P<pk>\d+)/members/$', cached(views.VLANMembersView.as_view()), name='vlan_members'),
+    url(r'^vlans/(?P<pk>\d+)/$', views.VLANView.as_view(), name='vlan'),
+    url(r'^vlans/(?P<pk>\d+)/members/$', views.VLANMembersView.as_view(), name='vlan_members'),
     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'),
-    url(r'^vlans/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='vlan_changelog', kwargs={'model': VLAN}),
+    url(r'^vlans/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='vlan_changelog', kwargs={'model': VLAN}),
 
 
     # Services
     # Services
-    url(r'^services/$', cached(views.ServiceListView.as_view()), name='service_list'),
+    url(r'^services/$', views.ServiceListView.as_view(), name='service_list'),
     url(r'^services/edit/$', views.ServiceBulkEditView.as_view(), name='service_bulk_edit'),
     url(r'^services/edit/$', views.ServiceBulkEditView.as_view(), name='service_bulk_edit'),
     url(r'^services/delete/$', views.ServiceBulkDeleteView.as_view(), name='service_bulk_delete'),
     url(r'^services/delete/$', views.ServiceBulkDeleteView.as_view(), name='service_bulk_delete'),
-    url(r'^services/(?P<pk>\d+)/$', cached(views.ServiceView.as_view()), name='service'),
+    url(r'^services/(?P<pk>\d+)/$', views.ServiceView.as_view(), name='service'),
     url(r'^services/(?P<pk>\d+)/edit/$', views.ServiceEditView.as_view(), name='service_edit'),
     url(r'^services/(?P<pk>\d+)/edit/$', views.ServiceEditView.as_view(), name='service_edit'),
     url(r'^services/(?P<pk>\d+)/delete/$', views.ServiceDeleteView.as_view(), name='service_delete'),
     url(r'^services/(?P<pk>\d+)/delete/$', views.ServiceDeleteView.as_view(), name='service_delete'),
-    url(r'^services/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='service_changelog', kwargs={'model': Service}),
+    url(r'^services/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='service_changelog', kwargs={'model': Service}),
 
 
 ]
 ]

+ 13 - 0
netbox/ipam/views.py

@@ -3,6 +3,8 @@ from django.conf import settings
 from django.contrib.auth.mixins import PermissionRequiredMixin
 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, redirect, render
 from django.shortcuts import get_object_or_404, redirect, render
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 from django_tables2 import RequestConfig
 from django_tables2 import RequestConfig
 
 
@@ -125,6 +127,7 @@ class VRFListView(PermissionRequiredMixin, ObjectListView):
 class VRFView(PermissionRequiredMixin, View):
 class VRFView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_vrf'
     permission_required = 'ipam.view_vrf'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         vrf = get_object_or_404(VRF.objects.all(), pk=pk)
         vrf = get_object_or_404(VRF.objects.all(), pk=pk)
@@ -319,6 +322,7 @@ class AggregateListView(PermissionRequiredMixin, ObjectListView):
 class AggregateView(PermissionRequiredMixin, View):
 class AggregateView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_aggregate'
     permission_required = 'ipam.view_aggregate'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         aggregate = get_object_or_404(Aggregate, pk=pk)
         aggregate = get_object_or_404(Aggregate, pk=pk)
@@ -456,6 +460,7 @@ class PrefixListView(PermissionRequiredMixin, ObjectListView):
 class PrefixView(PermissionRequiredMixin, View):
 class PrefixView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_prefix'
     permission_required = 'ipam.view_prefix'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         prefix = get_object_or_404(Prefix.objects.select_related(
         prefix = get_object_or_404(Prefix.objects.select_related(
@@ -500,6 +505,7 @@ class PrefixView(PermissionRequiredMixin, View):
 class PrefixPrefixesView(PermissionRequiredMixin, View):
 class PrefixPrefixesView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_prefix'
     permission_required = 'ipam.view_prefix'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
         prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
@@ -543,6 +549,7 @@ class PrefixPrefixesView(PermissionRequiredMixin, View):
 class PrefixIPAddressesView(PermissionRequiredMixin, View):
 class PrefixIPAddressesView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_prefix'
     permission_required = 'ipam.view_prefix'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
         prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
@@ -643,6 +650,7 @@ class IPAddressListView(PermissionRequiredMixin, ObjectListView):
 class IPAddressView(PermissionRequiredMixin, View):
 class IPAddressView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_ipaddress'
     permission_required = 'ipam.view_ipaddress'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         ipaddress = get_object_or_404(IPAddress.objects.select_related('vrf__tenant', 'tenant'), pk=pk)
         ipaddress = get_object_or_404(IPAddress.objects.select_related('vrf__tenant', 'tenant'), pk=pk)
@@ -726,6 +734,7 @@ class IPAddressAssignView(PermissionRequiredMixin, View):
 
 
         return super().dispatch(request, *args, **kwargs)
         return super().dispatch(request, *args, **kwargs)
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         form = forms.IPAddressAssignForm()
         form = forms.IPAddressAssignForm()
@@ -838,6 +847,7 @@ class VLANGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 class VLANGroupVLANsView(PermissionRequiredMixin, View):
 class VLANGroupVLANsView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_vlangroup'
     permission_required = 'ipam.view_vlangroup'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         vlan_group = get_object_or_404(VLANGroup.objects.all(), pk=pk)
         vlan_group = get_object_or_404(VLANGroup.objects.all(), pk=pk)
@@ -888,6 +898,7 @@ class VLANListView(PermissionRequiredMixin, ObjectListView):
 class VLANView(PermissionRequiredMixin, View):
 class VLANView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_vlan'
     permission_required = 'ipam.view_vlan'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         vlan = get_object_or_404(VLAN.objects.select_related(
         vlan = get_object_or_404(VLAN.objects.select_related(
@@ -906,6 +917,7 @@ class VLANView(PermissionRequiredMixin, View):
 class VLANMembersView(PermissionRequiredMixin, View):
 class VLANMembersView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_vlan'
     permission_required = 'ipam.view_vlan'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         vlan = get_object_or_404(VLAN.objects.all(), pk=pk)
         vlan = get_object_or_404(VLAN.objects.all(), pk=pk)
@@ -984,6 +996,7 @@ class ServiceListView(PermissionRequiredMixin, ObjectListView):
 class ServiceView(PermissionRequiredMixin, View):
 class ServiceView(PermissionRequiredMixin, View):
     permission_required = 'ipam.view_service'
     permission_required = 'ipam.view_service'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         service = get_object_or_404(Service, pk=pk)
         service = get_object_or_404(Service, pk=pk)

+ 7 - 10
netbox/netbox/configuration.example.py

@@ -60,18 +60,18 @@ BANNER_LOGIN = ''
 # BASE_PATH = 'netbox/'
 # BASE_PATH = 'netbox/'
 BASE_PATH = ''
 BASE_PATH = ''
 
 
-# Cache timeout in seconds. Set to `None` to enforce an infinate timeout. Set to 0 to dissable caching by immediatly
-# expiring keys. Defaults to 900 (15 minutes)
-CACHE_TIMEOUT = 900
-
-# Max number of entries (unique pages) to store in the cache at a time.
-CACHE_MAX_ENTRIES = 300
-
 # The fraction of entries that are culled when CACHE_MAX_ENTRIES is reached. The actual ratio is 1 / CACHE_CULL_FREQUENCY,
 # The fraction of entries that are culled when CACHE_MAX_ENTRIES is reached. The actual ratio is 1 / CACHE_CULL_FREQUENCY,
 # so set CACHE_CULL_FREQUENCY to 2 to cull half the entries when CACHE_MAX_ENTRIES is reached. This setting should be an
 # so set CACHE_CULL_FREQUENCY to 2 to cull half the entries when CACHE_MAX_ENTRIES is reached. This setting should be an
 # integer and defaults to 3
 # integer and defaults to 3
 CACHE_CULL_FREQUENCY = 3
 CACHE_CULL_FREQUENCY = 3
 
 
+# Max number of entries (unique pages) to store in the cache at a time.
+CACHE_MAX_ENTRIES = 300
+
+# Cache timeout in seconds. Set to `None` to enforce an infinate timeout. Set to 0 to dissable caching by immediatly
+# expiring keys. Defaults to 900 (15 minutes)
+CACHE_TIMEOUT = 900
+
 # Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
 # Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
 CHANGELOG_RETENTION = 90
 CHANGELOG_RETENTION = 90
 
 
@@ -171,9 +171,6 @@ TIME_ZONE = 'UTC'
 # database be configured and accessible by NetBox.
 # database be configured and accessible by NetBox.
 WEBHOOKS_ENABLED = False
 WEBHOOKS_ENABLED = False
 
 
-# Expose Prometheus monitoring metrics at `/metrics`
-PROMETHEUS_ENABLE = False
-
 # Date/time formatting. See the following link for supported formats:
 # Date/time formatting. See the following link for supported formats:
 # https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
 # https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
 DATE_FORMAT = 'N j, Y'
 DATE_FORMAT = 'N j, Y'

+ 2 - 13
netbox/netbox/settings.py

@@ -68,7 +68,6 @@ NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '')
 NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30)
 NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30)
 NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {})
 NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {})
 PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50)
 PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50)
-PROMETHEUS_ENABLE = getattr(configuration, 'PROMETHEUS_ENABLE', False)
 PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False)
 PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False)
 REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/')
 REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/')
 REDIS = getattr(configuration, 'REDIS', {})
 REDIS = getattr(configuration, 'REDIS', {})
@@ -118,10 +117,7 @@ else:
     ]
     ]
 
 
 # Database
 # Database
-if PROMETHEUS_ENABLE:
-    configuration.DATABASE.update({'ENGINE': 'django_prometheus.db.backends.postgresql'})
-else:
-    configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})
+configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})
 DATABASES = {
 DATABASES = {
     'default': configuration.DATABASE,
     'default': configuration.DATABASE,
 }
 }
@@ -164,7 +160,6 @@ INSTALLED_APPS = [
     'django.contrib.staticfiles',
     'django.contrib.staticfiles',
     'django.contrib.humanize',
     'django.contrib.humanize',
     'corsheaders',
     'corsheaders',
-    'django_prometheus',
     'django_redis',
     'django_redis',
     'debug_toolbar',
     'debug_toolbar',
     'django_filters',
     'django_filters',
@@ -193,7 +188,6 @@ if WEBHOOKS_ENABLED:
 # Middleware
 # Middleware
 MIDDLEWARE = (
 MIDDLEWARE = (
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
-    'django_prometheus.middleware.PrometheusBeforeMiddleware',
     'corsheaders.middleware.CorsMiddleware',
     'corsheaders.middleware.CorsMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.common.CommonMiddleware',
@@ -206,7 +200,6 @@ MIDDLEWARE = (
     'utilities.middleware.LoginRequiredMiddleware',
     'utilities.middleware.LoginRequiredMiddleware',
     'utilities.middleware.APIVersionMiddleware',
     'utilities.middleware.APIVersionMiddleware',
     'extras.middleware.ObjectChangeMiddleware',
     'extras.middleware.ObjectChangeMiddleware',
-    'django_prometheus.middleware.PrometheusAfterMiddleware',
 )
 )
 
 
 ROOT_URLCONF = 'netbox.urls'
 ROOT_URLCONF = 'netbox.urls'
@@ -239,11 +232,7 @@ if REDIS_PASSWORD:
     REDIS_CACHE_CON_STRING = '{}@{}'.format(REDIS_PASSWORD, REDIS_CACHE_CON_STRING)
     REDIS_CACHE_CON_STRING = '{}@{}'.format(REDIS_PASSWORD, REDIS_CACHE_CON_STRING)
 
 
 REDIS_CACHE_CON_STRING = '{}{}:{}/{}'.format(REDIS_CACHE_CON_STRING, REDIS_HOST, REDIS_PORT, REDIS_DATABASE)
 REDIS_CACHE_CON_STRING = '{}{}:{}/{}'.format(REDIS_CACHE_CON_STRING, REDIS_HOST, REDIS_PORT, REDIS_DATABASE)
-
-if PROMETHEUS_ENABLE:
-    CACHE_BACKEND = 'django_prometheus.cache.backends.redis.RedisCache'
-else:
-    CACHE_BACKEND = 'django_redis.cache.RedisCache'
+CACHE_BACKEND = 'django_redis.cache.RedisCache'
 
 
 CACHES = {
 CACHES = {
     "default": {
     "default": {

+ 4 - 10
netbox/netbox/urls.py

@@ -6,7 +6,6 @@ from drf_yasg.views import get_schema_view
 
 
 from netbox.views import APIRootView, HomeView, SearchView
 from netbox.views import APIRootView, HomeView, SearchView
 from users.views import LoginView, LogoutView
 from users.views import LoginView, LogoutView
-from utilities.urls import cached
 from .admin import admin_site
 from .admin import admin_site
 
 
 schema_view = get_schema_view(
 schema_view = get_schema_view(
@@ -25,11 +24,11 @@ schema_view = get_schema_view(
 _patterns = [
 _patterns = [
 
 
     # Base views
     # Base views
-    url(r'^$', cached(HomeView.as_view()), name='home'),
-    url(r'^search/$', cached(SearchView.as_view()), name='search'),
+    url(r'^$', HomeView.as_view(), name='home'),
+    url(r'^search/$', SearchView.as_view(), name='search'),
 
 
     # Login/logout
     # Login/logout
-    url(r'^login/$', cached(LoginView.as_view()), name='login'),
+    url(r'^login/$', LoginView.as_view(), name='login'),
     url(r'^logout/$', LogoutView.as_view(), name='logout'),
     url(r'^logout/$', LogoutView.as_view(), name='logout'),
 
 
     # Apps
     # Apps
@@ -43,7 +42,7 @@ _patterns = [
     url(r'^virtualization/', include('virtualization.urls')),
     url(r'^virtualization/', include('virtualization.urls')),
 
 
     # API
     # API
-    url(r'^api/$', cached(APIRootView.as_view()), name='api-root'),
+    url(r'^api/$', APIRootView.as_view(), name='api-root'),
     url(r'^api/circuits/', include('circuits.api.urls')),
     url(r'^api/circuits/', include('circuits.api.urls')),
     url(r'^api/dcim/', include('dcim.api.urls')),
     url(r'^api/dcim/', include('dcim.api.urls')),
     url(r'^api/extras/', include('extras.api.urls')),
     url(r'^api/extras/', include('extras.api.urls')),
@@ -68,11 +67,6 @@ if settings.WEBHOOKS_ENABLED:
         url(r'^admin/webhook-backend-status/', include('django_rq.urls')),
         url(r'^admin/webhook-backend-status/', include('django_rq.urls')),
     ]
     ]
 
 
-if settings.PROMETHEUS_ENABLE:
-    _patterns += [
-        url('', include('django_prometheus.urls')),
-    ]
-
 if settings.DEBUG:
 if settings.DEBUG:
     import debug_toolbar
     import debug_toolbar
     _patterns += [
     _patterns += [

+ 6 - 0
netbox/netbox/views.py

@@ -1,7 +1,10 @@
 from collections import OrderedDict
 from collections import OrderedDict
 
 
+from django.conf import settings
 from django.db.models import Count, F
 from django.db.models import Count, F
 from django.shortcuts import render
 from django.shortcuts import render
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 from rest_framework.response import Response
 from rest_framework.response import Response
 from rest_framework.reverse import reverse
 from rest_framework.reverse import reverse
@@ -160,6 +163,7 @@ SEARCH_TYPES = OrderedDict((
 class HomeView(View):
 class HomeView(View):
     template_name = 'home.html'
     template_name = 'home.html'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         connected_consoleports = ConsolePort.objects.filter(
         connected_consoleports = ConsolePort.objects.filter(
@@ -219,6 +223,7 @@ class HomeView(View):
 
 
 class SearchView(View):
 class SearchView(View):
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         # No query
         # No query
@@ -272,6 +277,7 @@ class APIRootView(APIView):
     def get_view_name(self):
     def get_view_name(self):
         return "API Root"
         return "API Root"
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, format=None):
     def get(self, request, format=None):
 
 
         return Response(OrderedDict((
         return Response(OrderedDict((

+ 6 - 7
netbox/secrets/urls.py

@@ -1,7 +1,6 @@
 from django.conf.urls import url
 from django.conf.urls import url
 
 
 from extras.views import ObjectChangeLogView
 from extras.views import ObjectChangeLogView
-from utilities.urls import cached
 from . import views
 from . import views
 from .models import Secret, SecretRole
 from .models import Secret, SecretRole
 
 
@@ -9,21 +8,21 @@ app_name = 'secrets'
 urlpatterns = [
 urlpatterns = [
 
 
     # Secret roles
     # Secret roles
-    url(r'^secret-roles/$', cached(views.SecretRoleListView.as_view()), name='secretrole_list'),
-    url(r'^secret-roles/add/$', cached(views.SecretRoleCreateView.as_view()), name='secretrole_add'),
+    url(r'^secret-roles/$', views.SecretRoleListView.as_view(), name='secretrole_list'),
+    url(r'^secret-roles/add/$', views.SecretRoleCreateView.as_view(), name='secretrole_add'),
     url(r'^secret-roles/import/$', views.SecretRoleBulkImportView.as_view(), name='secretrole_import'),
     url(r'^secret-roles/import/$', views.SecretRoleBulkImportView.as_view(), name='secretrole_import'),
     url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
     url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
     url(r'^secret-roles/(?P<slug>[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
     url(r'^secret-roles/(?P<slug>[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
-    url(r'^secret-roles/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='secretrole_changelog', kwargs={'model': SecretRole}),
+    url(r'^secret-roles/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}),
 
 
     # Secrets
     # Secrets
-    url(r'^secrets/$', cached(views.SecretListView.as_view()), name='secret_list'),
+    url(r'^secrets/$', views.SecretListView.as_view(), name='secret_list'),
     url(r'^secrets/import/$', views.SecretBulkImportView.as_view(), name='secret_import'),
     url(r'^secrets/import/$', views.SecretBulkImportView.as_view(), 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+)/$', cached(views.SecretView.as_view()), 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'),
-    url(r'^secrets/(?P<pk>\d+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='secret_changelog', kwargs={'model': Secret}),
+    url(r'^secrets/(?P<pk>\d+)/changelog/$', ObjectChangeLogView.as_view(), name='secret_changelog', kwargs={'model': Secret}),
 
 
 ]
 ]

+ 3 - 0
netbox/secrets/views.py

@@ -1,5 +1,6 @@
 import base64
 import base64
 
 
+from django.conf import settings
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.auth.decorators import permission_required, login_required
 from django.contrib.auth.decorators import permission_required, login_required
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.auth.mixins import PermissionRequiredMixin
@@ -7,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.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 
 
 from dcim.models import Device
 from dcim.models import Device
@@ -80,6 +82,7 @@ class SecretListView(PermissionRequiredMixin, ObjectListView):
 class SecretView(PermissionRequiredMixin, View):
 class SecretView(PermissionRequiredMixin, View):
     permission_required = 'secrets.view_secret'
     permission_required = 'secrets.view_secret'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         secret = get_object_or_404(Secret, pk=pk)
         secret = get_object_or_404(Secret, pk=pk)

+ 7 - 8
netbox/tenancy/urls.py

@@ -1,7 +1,6 @@
 from django.conf.urls import url
 from django.conf.urls import url
 
 
 from extras.views import ObjectChangeLogView
 from extras.views import ObjectChangeLogView
-from utilities.urls import cached
 from . import views
 from . import views
 from .models import Tenant, TenantGroup
 from .models import Tenant, TenantGroup
 
 
@@ -9,22 +8,22 @@ app_name = 'tenancy'
 urlpatterns = [
 urlpatterns = [
 
 
     # Tenant groups
     # Tenant groups
-    url(r'^tenant-groups/$', cached(views.TenantGroupListView.as_view()), name='tenantgroup_list'),
-    url(r'^tenant-groups/add/$', cached(views.TenantGroupCreateView.as_view()), name='tenantgroup_add'),
+    url(r'^tenant-groups/$', views.TenantGroupListView.as_view(), name='tenantgroup_list'),
+    url(r'^tenant-groups/add/$', views.TenantGroupCreateView.as_view(), name='tenantgroup_add'),
     url(r'^tenant-groups/import/$', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'),
     url(r'^tenant-groups/import/$', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'),
     url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
     url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
     url(r'^tenant-groups/(?P<slug>[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
     url(r'^tenant-groups/(?P<slug>[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
-    url(r'^tenant-groups/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
+    url(r'^tenant-groups/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
 
 
     # Tenants
     # Tenants
-    url(r'^tenants/$', cached(views.TenantListView.as_view()), name='tenant_list'),
-    url(r'^tenants/add/$', cached(views.TenantCreateView.as_view()), name='tenant_add'),
+    url(r'^tenants/$', views.TenantListView.as_view(), name='tenant_list'),
+    url(r'^tenants/add/$', views.TenantCreateView.as_view(), name='tenant_add'),
     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-]+)/$', cached(views.TenantView.as_view()), 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'),
-    url(r'^tenants/(?P<slug>[\w-]+)/changelog/$', cached(ObjectChangeLogView.as_view()), name='tenant_changelog', kwargs={'model': Tenant}),
+    url(r'^tenants/(?P<slug>[\w-]+)/changelog/$', ObjectChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}),
 
 
 ]
 ]

+ 4 - 0
netbox/tenancy/views.py

@@ -1,6 +1,9 @@
+from django.conf import settings
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.db.models import Count
 from django.db.models import Count
 from django.shortcuts import get_object_or_404, render
 from django.shortcuts import get_object_or_404, render
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 
 
 from circuits.models import Circuit
 from circuits.models import Circuit
@@ -66,6 +69,7 @@ class TenantListView(PermissionRequiredMixin, ObjectListView):
 class TenantView(PermissionRequiredMixin, View):
 class TenantView(PermissionRequiredMixin, View):
     permission_required = 'tenancy.view_tenant'
     permission_required = 'tenancy.view_tenant'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, slug):
     def get(self, request, slug):
 
 
         tenant = get_object_or_404(Tenant, slug=slug)
         tenant = get_object_or_404(Tenant, slug=slug)

+ 0 - 9
netbox/utilities/urls.py

@@ -1,9 +0,0 @@
-from django.conf import settings
-from django.views.decorators.cache import cache_page
-
-
-def cached(view):
-    """
-    Return a cache_page decorated view
-    """
-    return cache_page(settings.CACHE_TIMEOUT)(view)

+ 4 - 0
netbox/utilities/views.py

@@ -17,6 +17,8 @@ from django.urls import reverse
 from django.utils.html import escape
 from django.utils.html import escape
 from django.utils.http import is_safe_url
 from django.utils.http import is_safe_url
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.decorators.csrf import requires_csrf_token
 from django.views.decorators.csrf import requires_csrf_token
 from django.views.defaults import ERROR_500_TEMPLATE_NAME
 from django.views.defaults import ERROR_500_TEMPLATE_NAME
 from django.views.generic import View
 from django.views.generic import View
@@ -106,6 +108,7 @@ class ObjectListView(View):
 
 
         return csv_data
         return csv_data
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request):
     def get(self, request):
 
 
         model = self.queryset.model
         model = self.queryset.model
@@ -713,6 +716,7 @@ class ComponentCreateView(View):
     model_form = None
     model_form = None
     template_name = None
     template_name = None
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         parent = get_object_or_404(self.parent_model, pk=pk)
         parent = get_object_or_404(self.parent_model, pk=pk)

+ 6 - 0
netbox/virtualization/views.py

@@ -1,9 +1,12 @@
+from django.conf import settings
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.contrib.auth.mixins import PermissionRequiredMixin
 from django.db import transaction
 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.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_page
 from django.views.generic import View
 from django.views.generic import View
 
 
 from dcim.models import Device, Interface
 from dcim.models import Device, Interface
@@ -106,6 +109,7 @@ class ClusterListView(PermissionRequiredMixin, ObjectListView):
 class ClusterView(PermissionRequiredMixin, View):
 class ClusterView(PermissionRequiredMixin, View):
     permission_required = 'virtualization.view_cluster'
     permission_required = 'virtualization.view_cluster'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         cluster = get_object_or_404(Cluster, pk=pk)
         cluster = get_object_or_404(Cluster, pk=pk)
@@ -168,6 +172,7 @@ class ClusterAddDevicesView(PermissionRequiredMixin, View):
     form = forms.ClusterAddDevicesForm
     form = forms.ClusterAddDevicesForm
     template_name = 'virtualization/cluster_add_devices.html'
     template_name = 'virtualization/cluster_add_devices.html'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         cluster = get_object_or_404(Cluster, pk=pk)
         cluster = get_object_or_404(Cluster, pk=pk)
@@ -263,6 +268,7 @@ class VirtualMachineListView(PermissionRequiredMixin, ObjectListView):
 class VirtualMachineView(PermissionRequiredMixin, View):
 class VirtualMachineView(PermissionRequiredMixin, View):
     permission_required = 'virtualization.view_virtualmachine'
     permission_required = 'virtualization.view_virtualmachine'
 
 
+    @method_decorator(cache_page(settings.CACHE_TIMEOUT))
     def get(self, request, pk):
     def get(self, request, pk):
 
 
         virtualmachine = get_object_or_404(VirtualMachine.objects.select_related('tenant__group'), pk=pk)
         virtualmachine = get_object_or_404(VirtualMachine.objects.select_related('tenant__group'), pk=pk)

+ 0 - 1
requirements.txt

@@ -3,7 +3,6 @@ django-cors-headers==2.4.0
 django-debug-toolbar==1.11
 django-debug-toolbar==1.11
 django-filter==2.0.0
 django-filter==2.0.0
 django-mptt==0.9.1
 django-mptt==0.9.1
-django-prometheus==1.0.15
 django-redis==4.5.0
 django-redis==4.5.0
 django-tables2==2.0.3
 django-tables2==2.0.3
 django-taggit==0.23.0
 django-taggit==0.23.0