diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 64028dab3..95e98df2f 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -360,6 +360,15 @@ class Rack(CreatedUpdatedModel): def get_0u_devices(self): return self.devices.filter(position=0) + def get_utilization(self): + """ + Determine the utilization rate of the rack and return it as a percentage. + """ + if self.u_consumed is None: + self.u_consumed = 0 + u_available = self.u_height - self.u_consumed + return int(float(self.u_height - u_available) / self.u_height * 100) + # # Device Types diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index dc66c3ab1..0fe2c6834 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -48,6 +48,18 @@ STATUS_ICON = """ {% endif %} """ +UTILIZATION_GRAPH = """ +{% with record.get_utilization as percentage %} +
+ {% if percentage < 15 %}{{ percentage }}%{% endif %} +
+ {% if percentage >= 15 %}{{ percentage }}%{% endif %} +
+
+{% endwith %} +""" + # # Sites @@ -97,6 +109,8 @@ class RackTable(BaseTable): group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group') facility_id = tables.Column(verbose_name='Facility ID') u_height = tables.Column(verbose_name='Height (U)') + u_consumed = tables.Column(accessor=Accessor('u_consumed'), verbose_name='Used (U)') + utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization') devices = tables.Column(accessor=Accessor('device_count'), verbose_name='Devices') class Meta(BaseTable.Meta): diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index d59d5496b..5f8434bcc 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -7,7 +7,7 @@ from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse -from django.db.models import Count, ProtectedError +from django.db.models import Count, ProtectedError, Sum from django.forms import ModelMultipleChoiceField, MultipleHiddenInput from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render @@ -144,7 +144,7 @@ class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): # class RackListView(ObjectListView): - queryset = Rack.objects.select_related('site', 'group').annotate(device_count=Count('devices', distinct=True)) + queryset = Rack.objects.select_related('site').prefetch_related('devices__device_type').annotate(device_count=Count('devices', distinct=True), u_consumed=Sum('devices__device_type__u_height')) filter = filters.RackFilter filter_form = forms.RackFilterForm table = tables.RackTable