mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Implement get_subquery() for annotation of child object counts; Rename dcim.Site 'count_*' fields
This commit is contained in:
parent
7d41a9ccdb
commit
f4bbdf30e8
@ -155,6 +155,8 @@ functionality provided by the front end UI.
|
|||||||
* dcim.DeviceType: `instance_count` has been renamed to `device_count`.
|
* dcim.DeviceType: `instance_count` has been renamed to `device_count`.
|
||||||
* dcim.Interface: `form_factor` has been renamed to `type`. Backward compatibility for `form_factor` will be maintained until NetBox v2.7.
|
* dcim.Interface: `form_factor` has been renamed to `type`. Backward compatibility for `form_factor` will be maintained until NetBox v2.7.
|
||||||
* dcim.Interface: The `type` filter has been renamed to `kind`.
|
* dcim.Interface: The `type` filter has been renamed to `kind`.
|
||||||
|
* dcim.Site: The `count_*` read-only fields have been renamed to `*_count` for consistency with other objects.
|
||||||
|
* dcim.Site: Added the `virtualmachine_count` read-only field.
|
||||||
* extras.Tag: Added `color` and `comments` fields to the Tag serializer.
|
* extras.Tag: Added `color` and `comments` fields to the Tag serializer.
|
||||||
* virtualization.VirtualMachine: The virtual machines list endpoint now includes rendered context data.
|
* virtualization.VirtualMachine: The virtual machines list endpoint now includes rendered context data.
|
||||||
|
|
||||||
|
@ -72,19 +72,20 @@ class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
time_zone = TimeZoneField(required=False)
|
time_zone = TimeZoneField(required=False)
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
count_prefixes = serializers.IntegerField(read_only=True)
|
prefix_count = serializers.IntegerField(read_only=True)
|
||||||
count_vlans = serializers.IntegerField(read_only=True)
|
vlan_count = serializers.IntegerField(read_only=True)
|
||||||
count_racks = serializers.IntegerField(read_only=True)
|
rack_count = serializers.IntegerField(read_only=True)
|
||||||
count_devices = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
count_circuits = serializers.IntegerField(read_only=True)
|
circuit_count = serializers.IntegerField(read_only=True)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description',
|
'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description',
|
||||||
'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone',
|
'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone',
|
||||||
'contact_email', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'count_prefixes',
|
'contact_email', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'prefix_count',
|
||||||
'count_vlans', 'count_racks', 'count_devices', 'count_circuits',
|
'vlan_count', 'rack_count', 'device_count', 'circuit_count', 'virtualmachine_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from rest_framework.mixins import ListModelMixin
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import GenericViewSet, ViewSet
|
from rest_framework.viewsets import GenericViewSet, ViewSet
|
||||||
|
|
||||||
|
from circuits.models import Circuit
|
||||||
from dcim import filters
|
from dcim import filters
|
||||||
from dcim.models import (
|
from dcim.models import (
|
||||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||||
@ -23,9 +24,11 @@ from dcim.models import (
|
|||||||
from extras.api.serializers import RenderedGraphSerializer
|
from extras.api.serializers import RenderedGraphSerializer
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
|
||||||
|
from ipam.models import Prefix, VLAN
|
||||||
from utilities.api import (
|
from utilities.api import (
|
||||||
get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
|
get_serializer_for_model, IsAuthenticatedOrLoginNotRequired, FieldChoicesViewSet, ModelViewSet, ServiceUnavailable,
|
||||||
)
|
)
|
||||||
|
from utilities.utils import get_subquery
|
||||||
from virtualization.models import VirtualMachine
|
from virtualization.models import VirtualMachine
|
||||||
from . import serializers
|
from . import serializers
|
||||||
from .exceptions import MissingFilterException
|
from .exceptions import MissingFilterException
|
||||||
@ -106,7 +109,18 @@ class RegionViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SiteViewSet(CustomFieldModelViewSet):
|
class SiteViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Site.objects.select_related('region', 'tenant').prefetch_related('tags')
|
queryset = Site.objects.select_related(
|
||||||
|
'region', 'tenant'
|
||||||
|
).prefetch_related(
|
||||||
|
'tags'
|
||||||
|
).annotate(
|
||||||
|
device_count=get_subquery(Device, 'site'),
|
||||||
|
rack_count=get_subquery(Rack, 'site'),
|
||||||
|
prefix_count=get_subquery(Prefix, 'site'),
|
||||||
|
vlan_count=get_subquery(VLAN, 'site'),
|
||||||
|
circuit_count=get_subquery(Circuit, 'terminations__site'),
|
||||||
|
virtualmachine_count=get_subquery(VirtualMachine, 'cluster__site'),
|
||||||
|
)
|
||||||
serializer_class = serializers.SiteSerializer
|
serializer_class = serializers.SiteSerializer
|
||||||
filterset_class = filters.SiteFilter
|
filterset_class = filters.SiteFilter
|
||||||
|
|
||||||
@ -281,15 +295,9 @@ class DeviceBayTemplateViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class DeviceRoleViewSet(ModelViewSet):
|
class DeviceRoleViewSet(ModelViewSet):
|
||||||
device_count = Device.objects.filter(
|
|
||||||
device_role=OuterRef('pk')
|
|
||||||
).order_by().values('device_role').annotate(c=Count('*')).values('c')
|
|
||||||
virtualmachine_count = VirtualMachine.objects.filter(
|
|
||||||
role=OuterRef('pk')
|
|
||||||
).order_by().values('role').annotate(c=Count('*')).values('c')
|
|
||||||
queryset = DeviceRole.objects.annotate(
|
queryset = DeviceRole.objects.annotate(
|
||||||
device_count=Subquery(device_count),
|
device_count=get_subquery(Device, 'device_role'),
|
||||||
virtualmachine_count=Subquery(virtualmachine_count)
|
virtualmachine_count=get_subquery(VirtualMachine, 'role')
|
||||||
)
|
)
|
||||||
serializer_class = serializers.DeviceRoleSerializer
|
serializer_class = serializers.DeviceRoleSerializer
|
||||||
filterset_class = filters.DeviceRoleFilter
|
filterset_class = filters.DeviceRoleFilter
|
||||||
@ -300,15 +308,9 @@ class DeviceRoleViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class PlatformViewSet(ModelViewSet):
|
class PlatformViewSet(ModelViewSet):
|
||||||
device_count = Device.objects.filter(
|
|
||||||
platform=OuterRef('pk')
|
|
||||||
).order_by().values('platform').annotate(c=Count('*')).values('c')
|
|
||||||
virtualmachine_count = VirtualMachine.objects.filter(
|
|
||||||
platform=OuterRef('pk')
|
|
||||||
).order_by().values('platform').annotate(c=Count('*')).values('c')
|
|
||||||
queryset = Platform.objects.annotate(
|
queryset = Platform.objects.annotate(
|
||||||
device_count=Subquery(device_count),
|
device_count=get_subquery(Device, 'platform'),
|
||||||
virtualmachine_count=Subquery(virtualmachine_count)
|
virtualmachine_count=get_subquery(VirtualMachine, 'platform')
|
||||||
)
|
)
|
||||||
serializer_class = serializers.PlatformSerializer
|
serializer_class = serializers.PlatformSerializer
|
||||||
filterset_class = filters.PlatformFilter
|
filterset_class = filters.PlatformFilter
|
||||||
|
@ -363,32 +363,6 @@ class Site(ChangeLoggedModel, CustomFieldModel):
|
|||||||
def get_status_class(self):
|
def get_status_class(self):
|
||||||
return STATUS_CLASSES[self.status]
|
return STATUS_CLASSES[self.status]
|
||||||
|
|
||||||
@property
|
|
||||||
def count_prefixes(self):
|
|
||||||
return self.prefixes.count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def count_vlans(self):
|
|
||||||
return self.vlans.count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def count_racks(self):
|
|
||||||
return Rack.objects.filter(site=self).count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def count_devices(self):
|
|
||||||
return Device.objects.filter(site=self).count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def count_circuits(self):
|
|
||||||
from circuits.models import Circuit
|
|
||||||
return Circuit.objects.filter(terminations__site=self).count()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def count_vms(self):
|
|
||||||
from virtualization.models import VirtualMachine
|
|
||||||
return VirtualMachine.objects.filter(cluster__site=self).count()
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Racks
|
# Racks
|
||||||
|
@ -10,6 +10,7 @@ from extras.api.views import CustomFieldModelViewSet
|
|||||||
from ipam import filters
|
from ipam import filters
|
||||||
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||||
from utilities.api import FieldChoicesViewSet, ModelViewSet
|
from utilities.api import FieldChoicesViewSet, ModelViewSet
|
||||||
|
from utilities.utils import get_subquery
|
||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
@ -66,15 +67,9 @@ class AggregateViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RoleViewSet(ModelViewSet):
|
class RoleViewSet(ModelViewSet):
|
||||||
prefix_count = Prefix.objects.filter(
|
|
||||||
role=OuterRef('pk')
|
|
||||||
).order_by().values('role').annotate(c=Count('*')).values('c')
|
|
||||||
vlan_count = VLAN.objects.filter(
|
|
||||||
role=OuterRef('pk')
|
|
||||||
).order_by().values('role').annotate(c=Count('*')).values('c')
|
|
||||||
queryset = Role.objects.annotate(
|
queryset = Role.objects.annotate(
|
||||||
prefix_count=Subquery(prefix_count),
|
prefix_count=get_subquery(Prefix, 'role'),
|
||||||
vlan_count=Subquery(vlan_count)
|
vlan_count=get_subquery(VLAN, 'role')
|
||||||
)
|
)
|
||||||
serializer_class = serializers.RoleSerializer
|
serializer_class = serializers.RoleSerializer
|
||||||
filterset_class = filters.RoleFilter
|
filterset_class = filters.RoleFilter
|
||||||
|
@ -4,6 +4,7 @@ import datetime
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from django.core.serializers import serialize
|
from django.core.serializers import serialize
|
||||||
|
from django.db.models import Count, OuterRef, Subquery
|
||||||
|
|
||||||
from dcim.constants import LENGTH_UNIT_CENTIMETER, LENGTH_UNIT_FOOT, LENGTH_UNIT_INCH, LENGTH_UNIT_METER
|
from dcim.constants import LENGTH_UNIT_CENTIMETER, LENGTH_UNIT_FOOT, LENGTH_UNIT_INCH, LENGTH_UNIT_METER
|
||||||
|
|
||||||
@ -71,6 +72,23 @@ def model_names_to_filter_dict(names):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_subquery(model, field):
|
||||||
|
"""
|
||||||
|
Return a Subquery suitable for annotating a child object count.
|
||||||
|
"""
|
||||||
|
subquery = Subquery(
|
||||||
|
model.objects.filter(
|
||||||
|
**{field: OuterRef('pk')}
|
||||||
|
).order_by().values(
|
||||||
|
field
|
||||||
|
).annotate(
|
||||||
|
c=Count('*')
|
||||||
|
).values('c')
|
||||||
|
)
|
||||||
|
|
||||||
|
return subquery
|
||||||
|
|
||||||
|
|
||||||
def serialize_object(obj, extra=None):
|
def serialize_object(obj, extra=None):
|
||||||
"""
|
"""
|
||||||
Return a generic JSON representation of an object using Django's built-in serializer. (This is used for things like
|
Return a generic JSON representation of an object using Django's built-in serializer. (This is used for things like
|
||||||
|
Loading…
Reference in New Issue
Block a user