Closes #11738: Annotate utilization on VLAN groups (#13108)

* Update serializers.py

* Update vlans.py

* Update vlans.py

* Update vlangroup.html

* Update vlans.py

* Update vlans.py

* Update serializers.py

* adds db annotation to calculate utilization

* optimize queries

* merge fix

* adds round function for utilization to limit decimal

* fixed object view annotation

* consolidated queryset for utilization

* lint fixes

* Renamed manager method to annotate_utilization() for consistency with other managers

---------

Co-authored-by: Abhimanyu Saharan <desk.abhimanyu@gmail.com>
This commit is contained in:
Jeremy Stretch 2023-07-06 14:51:28 -04:00 committed by GitHub
parent 62bdb90f61
commit 7419a8e112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 38 additions and 19 deletions

View File

@ -218,12 +218,13 @@ class VLANGroupSerializer(NetBoxModelSerializer):
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
scope = serializers.SerializerMethodField(read_only=True)
vlan_count = serializers.IntegerField(read_only=True)
utilization = serializers.CharField(read_only=True)
class Meta:
model = VLANGroup
fields = [
'id', 'url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'min_vid', 'max_vid',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization'
]
validators = []

View File

@ -1,5 +1,7 @@
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import transaction
from django.db.models import F
from django.db.models.functions import Round
from django.shortcuts import get_object_or_404
from django_pglocks import advisory_lock
from drf_spectacular.utils import extend_schema
@ -145,9 +147,7 @@ class FHRPGroupAssignmentViewSet(NetBoxModelViewSet):
class VLANGroupViewSet(NetBoxModelViewSet):
queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group')
).prefetch_related('tags')
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
serializer_class = serializers.VLANGroupSerializer
filterset_class = filtersets.VLANGroupFilterSet

View File

@ -9,7 +9,7 @@ from django.utils.translation import gettext as _
from dcim.models import Interface
from ipam.choices import *
from ipam.constants import *
from ipam.querysets import VLANQuerySet
from ipam.querysets import VLANQuerySet, VLANGroupQuerySet
from netbox.models import OrganizationalModel, PrimaryModel
from virtualization.models import VMInterface
@ -63,6 +63,8 @@ class VLANGroup(OrganizationalModel):
help_text=_('Highest permissible ID of a child VLAN')
)
objects = VLANGroupQuerySet.as_manager()
class Meta:
ordering = ('name', 'pk') # Name may be non-unique
constraints = (

View File

@ -1,8 +1,10 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models import Count, OuterRef, Q, Subquery, Value
from django.db.models import Count, F, OuterRef, Q, Subquery, Value
from django.db.models.expressions import RawSQL
from django.db.models.functions import Round
from utilities.querysets import RestrictedQuerySet
from utilities.utils import count_related
__all__ = (
'ASNRangeQuerySet',
@ -54,6 +56,17 @@ class PrefixQuerySet(RestrictedQuerySet):
)
class VLANGroupQuerySet(RestrictedQuerySet):
def annotate_utilization(self):
from .models import VLAN
return self.annotate(
vlan_count=count_related(VLAN, 'group'),
utilization=Round(F('vlan_count') / (F('max_vid') - F('min_vid') + 1.0) * 100, 2)
)
class VLANQuerySet(RestrictedQuerySet):
def get_for_device(self, device):

View File

@ -70,6 +70,10 @@ class VLANGroupTable(NetBoxTable):
url_params={'group_id': 'pk'},
verbose_name='VLANs'
)
utilization = columns.UtilizationColumn(
orderable=False,
verbose_name='Utilization'
)
tags = columns.TagColumn(
url_name='ipam:vlangroup_list'
)
@ -81,9 +85,9 @@ class VLANGroupTable(NetBoxTable):
model = VLANGroup
fields = (
'pk', 'id', 'name', 'scope_type', 'scope', 'min_vid', 'max_vid', 'vlan_count', 'slug', 'description',
'tags', 'created', 'last_updated', 'actions',
'tags', 'created', 'last_updated', 'actions', 'utilization',
)
default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'description')
default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'utilization', 'description')
#

View File

@ -1,6 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models import Prefetch
from django.db.models import F, Prefetch
from django.db.models.expressions import RawSQL
from django.db.models.functions import Round
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext as _
@ -882,9 +883,7 @@ class IPAddressRelatedIPsView(generic.ObjectChildrenView):
#
class VLANGroupListView(generic.ObjectListView):
queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group')
)
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
filterset = filtersets.VLANGroupFilterSet
filterset_form = forms.VLANGroupFilterForm
table = tables.VLANGroupTable
@ -892,7 +891,7 @@ class VLANGroupListView(generic.ObjectListView):
@register_model_view(VLANGroup)
class VLANGroupView(generic.ObjectView):
queryset = VLANGroup.objects.all()
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
def get_extra_context(self, request, instance):
related_models = (
@ -934,18 +933,14 @@ class VLANGroupBulkImportView(generic.BulkImportView):
class VLANGroupBulkEditView(generic.BulkEditView):
queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group')
)
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable
form = forms.VLANGroupBulkEditForm
class VLANGroupBulkDeleteView(generic.BulkDeleteView):
queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group')
)
queryset = VLANGroup.objects.annotate_utilization().prefetch_related('tags')
filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable

View File

@ -42,6 +42,10 @@
<th scope="row">Permitted VIDs</th>
<td>{{ object.min_vid }} - {{ object.max_vid }}</td>
</tr>
<tr>
<th scope="row">Utilization</th>
<td>{% utilization_graph object.utilization %}</td>
</tr>
</table>
</div>
</div>