Add RelatedObjectCountFields to serializers; remove static annotations from querysets

This commit is contained in:
Jeremy Stretch 2024-02-14 12:02:14 -05:00
parent afb5f42af3
commit 701f461225
21 changed files with 157 additions and 201 deletions

View File

@ -1,8 +1,8 @@
from drf_spectacular.utils import extend_schema_field, extend_schema_serializer from drf_spectacular.utils import extend_schema_serializer
from drf_spectacular.types import OpenApiTypes
from rest_framework import serializers from rest_framework import serializers
from circuits.models import * from circuits.models import *
from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import WritableNestedSerializer from netbox.api.serializers import WritableNestedSerializer
__all__ = [ __all__ = [
@ -36,7 +36,7 @@ class NestedProviderNetworkSerializer(WritableNestedSerializer):
) )
class NestedProviderSerializer(WritableNestedSerializer): class NestedProviderSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail')
circuit_count = serializers.IntegerField(read_only=True) circuit_count = RelatedObjectCountField('circuits.circuit', 'provider')
class Meta: class Meta:
model = Provider model = Provider
@ -64,7 +64,7 @@ class NestedProviderAccountSerializer(WritableNestedSerializer):
) )
class NestedCircuitTypeSerializer(WritableNestedSerializer): class NestedCircuitTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail')
circuit_count = serializers.IntegerField(read_only=True) circuit_count = RelatedObjectCountField('circuits.circuit', 'type')
class Meta: class Meta:
model = CircuitType model = CircuitType

View File

@ -6,7 +6,7 @@ from dcim.api.nested_serializers import NestedSiteSerializer
from dcim.api.serializers import CabledObjectSerializer from dcim.api.serializers import CabledObjectSerializer
from ipam.models import ASN from ipam.models import ASN
from ipam.api.nested_serializers import NestedASNSerializer from ipam.api.nested_serializers import NestedASNSerializer
from netbox.api.fields import ChoiceField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
from tenancy.api.nested_serializers import NestedTenantSerializer from tenancy.api.nested_serializers import NestedTenantSerializer
from .nested_serializers import * from .nested_serializers import *
@ -32,7 +32,7 @@ class ProviderSerializer(NetBoxModelSerializer):
) )
# Related object counts # Related object counts
circuit_count = serializers.IntegerField(read_only=True) circuit_count = RelatedObjectCountField('circuits.circuit', 'provider')
class Meta: class Meta:
model = Provider model = Provider
@ -80,13 +80,15 @@ class ProviderNetworkSerializer(NetBoxModelSerializer):
class CircuitTypeSerializer(NetBoxModelSerializer): class CircuitTypeSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail')
circuit_count = serializers.IntegerField(read_only=True)
# Related object counts
circuit_count = RelatedObjectCountField('circuits.circuit', 'type')
class Meta: class Meta:
model = CircuitType model = CircuitType
fields = [ fields = [
'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
'circuit_count', 'last_updated', 'circuit_count',
] ]

View File

@ -4,7 +4,6 @@ from circuits import filtersets
from circuits.models import * from circuits.models import *
from dcim.api.views import PassThroughPortMixin from dcim.api.views import PassThroughPortMixin
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from utilities.utils import count_related
from . import serializers from . import serializers
@ -21,9 +20,7 @@ class CircuitsRootView(APIRootView):
# #
class ProviderViewSet(NetBoxModelViewSet): class ProviderViewSet(NetBoxModelViewSet):
queryset = Provider.objects.annotate( queryset = Provider.objects.all()
circuit_count=count_related(Circuit, 'provider')
)
serializer_class = serializers.ProviderSerializer serializer_class = serializers.ProviderSerializer
filterset_class = filtersets.ProviderFilterSet filterset_class = filtersets.ProviderFilterSet
@ -33,9 +30,7 @@ class ProviderViewSet(NetBoxModelViewSet):
# #
class CircuitTypeViewSet(NetBoxModelViewSet): class CircuitTypeViewSet(NetBoxModelViewSet):
queryset = CircuitType.objects.annotate( queryset = CircuitType.objects.all()
circuit_count=count_related(Circuit, 'type')
)
serializer_class = serializers.CircuitTypeSerializer serializer_class = serializers.CircuitTypeSerializer
filterset_class = filtersets.CircuitTypeFilterSet filterset_class = filtersets.CircuitTypeFilterSet

View File

@ -2,7 +2,7 @@ from rest_framework import serializers
from core.choices import * from core.choices import *
from core.models import * from core.models import *
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from users.api.nested_serializers import NestedUserSerializer from users.api.nested_serializers import NestedUserSerializer
@ -28,9 +28,7 @@ class DataSourceSerializer(NetBoxModelSerializer):
) )
# Related object counts # Related object counts
file_count = serializers.IntegerField( file_count = RelatedObjectCountField('core.datafile', 'source')
read_only=True
)
class Meta: class Meta:
model = DataSource model = DataSource

View File

@ -9,7 +9,6 @@ from rest_framework.viewsets import ReadOnlyModelViewSet
from core import filtersets from core import filtersets
from core.models import * from core.models import *
from netbox.api.viewsets import NetBoxModelViewSet, NetBoxReadOnlyModelViewSet from netbox.api.viewsets import NetBoxModelViewSet, NetBoxReadOnlyModelViewSet
from utilities.utils import count_related
from . import serializers from . import serializers
@ -22,9 +21,7 @@ class CoreRootView(APIRootView):
class DataSourceViewSet(NetBoxModelViewSet): class DataSourceViewSet(NetBoxModelViewSet):
queryset = DataSource.objects.annotate( queryset = DataSource.objects.all()
file_count=count_related(DataFile, 'source')
)
serializer_class = serializers.DataSourceSerializer serializer_class = serializers.DataSourceSerializer
filterset_class = filtersets.DataSourceFilterSet filterset_class = filtersets.DataSourceFilterSet

View File

@ -2,7 +2,8 @@ from drf_spectacular.utils import extend_schema_serializer
from rest_framework import serializers from rest_framework import serializers
from dcim import models from dcim import models
from netbox.api.serializers import BaseModelSerializer, WritableNestedSerializer from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import WritableNestedSerializer
__all__ = [ __all__ = [
'ComponentNestedModuleSerializer', 'ComponentNestedModuleSerializer',
@ -110,7 +111,7 @@ class NestedLocationSerializer(WritableNestedSerializer):
) )
class NestedRackRoleSerializer(WritableNestedSerializer): class NestedRackRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
rack_count = serializers.IntegerField(read_only=True) rack_count = RelatedObjectCountField('dcim.rack', 'role')
class Meta: class Meta:
model = models.RackRole model = models.RackRole
@ -122,7 +123,7 @@ class NestedRackRoleSerializer(WritableNestedSerializer):
) )
class NestedRackSerializer(WritableNestedSerializer): class NestedRackSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
device_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'rack')
class Meta: class Meta:
model = models.Rack model = models.Rack
@ -150,7 +151,7 @@ class NestedRackReservationSerializer(WritableNestedSerializer):
) )
class NestedManufacturerSerializer(WritableNestedSerializer): class NestedManufacturerSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
devicetype_count = serializers.IntegerField(read_only=True) devicetype_count = RelatedObjectCountField('dcim.devicetype', 'manufacturer')
class Meta: class Meta:
model = models.Manufacturer model = models.Manufacturer
@ -163,7 +164,7 @@ class NestedManufacturerSerializer(WritableNestedSerializer):
class NestedDeviceTypeSerializer(WritableNestedSerializer): class NestedDeviceTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
manufacturer = NestedManufacturerSerializer(read_only=True) manufacturer = NestedManufacturerSerializer(read_only=True)
device_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'device_type')
class Meta: class Meta:
model = models.DeviceType model = models.DeviceType
@ -173,7 +174,6 @@ class NestedDeviceTypeSerializer(WritableNestedSerializer):
class NestedModuleTypeSerializer(WritableNestedSerializer): class NestedModuleTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
manufacturer = NestedManufacturerSerializer(read_only=True) manufacturer = NestedManufacturerSerializer(read_only=True)
# module_count = serializers.IntegerField(read_only=True)
class Meta: class Meta:
model = models.ModuleType model = models.ModuleType
@ -274,8 +274,8 @@ class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
) )
class NestedDeviceRoleSerializer(WritableNestedSerializer): class NestedDeviceRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
device_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'role')
virtualmachine_count = serializers.IntegerField(read_only=True) virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'role')
class Meta: class Meta:
model = models.DeviceRole model = models.DeviceRole
@ -287,8 +287,8 @@ class NestedDeviceRoleSerializer(WritableNestedSerializer):
) )
class NestedPlatformSerializer(WritableNestedSerializer): class NestedPlatformSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
device_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'platform')
virtualmachine_count = serializers.IntegerField(read_only=True) virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'platform')
class Meta: class Meta:
model = models.Platform model = models.Platform
@ -445,7 +445,7 @@ class NestedInventoryItemSerializer(WritableNestedSerializer):
) )
class NestedInventoryItemRoleSerializer(WritableNestedSerializer): class NestedInventoryItemRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail')
inventoryitem_count = serializers.IntegerField(read_only=True) inventoryitem_count = RelatedObjectCountField('dcim.inventoryitem', 'role')
class Meta: class Meta:
model = models.InventoryItemRole model = models.InventoryItemRole
@ -490,7 +490,7 @@ class NestedVirtualChassisSerializer(WritableNestedSerializer):
) )
class NestedPowerPanelSerializer(WritableNestedSerializer): class NestedPowerPanelSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
powerfeed_count = serializers.IntegerField(read_only=True) powerfeed_count = RelatedObjectCountField('dcim.powerfeed', 'power_panel')
class Meta: class Meta:
model = models.PowerPanel model = models.PowerPanel

View File

@ -15,7 +15,7 @@ from ipam.api.nested_serializers import (
NestedASNSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer, NestedASNSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer,
) )
from ipam.models import ASN, VLAN from ipam.models import ASN, VLAN
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import ( from netbox.api.serializers import (
GenericObjectSerializer, NestedGroupModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer, GenericObjectSerializer, NestedGroupModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer,
WritableNestedSerializer, WritableNestedSerializer,
@ -144,12 +144,12 @@ class SiteSerializer(NetBoxModelSerializer):
) )
# Related object counts # Related object counts
circuit_count = serializers.IntegerField(read_only=True) circuit_count = RelatedObjectCountField('circuits.circuit', 'terminations__site')
device_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'site')
prefix_count = serializers.IntegerField(read_only=True) prefix_count = RelatedObjectCountField('ipam.prefix', 'site')
rack_count = serializers.IntegerField(read_only=True) rack_count = RelatedObjectCountField('dcim.rack', 'site')
virtualmachine_count = serializers.IntegerField(read_only=True) vlan_count = RelatedObjectCountField('ipam.vlan', 'site')
vlan_count = serializers.IntegerField(read_only=True) virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'site')
class Meta: class Meta:
model = Site model = Site
@ -184,7 +184,9 @@ class LocationSerializer(NestedGroupModelSerializer):
class RackRoleSerializer(NetBoxModelSerializer): class RackRoleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
rack_count = serializers.IntegerField(read_only=True)
# Related object counts
rack_count = RelatedObjectCountField('dcim.rack', 'role')
class Meta: class Meta:
model = RackRole model = RackRole
@ -207,8 +209,10 @@ class RackSerializer(NetBoxModelSerializer):
width = ChoiceField(choices=RackWidthChoices, required=False) width = ChoiceField(choices=RackWidthChoices, required=False)
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False, allow_null=True) outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False, allow_null=True)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True) weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
device_count = serializers.IntegerField(read_only=True)
powerfeed_count = serializers.IntegerField(read_only=True) # Related object counts
device_count = RelatedObjectCountField('dcim.device', 'rack')
powerfeed_count = RelatedObjectCountField('dcim.powerfeed', 'rack')
class Meta: class Meta:
model = Rack model = Rack
@ -299,9 +303,11 @@ class RackElevationDetailFilterSerializer(serializers.Serializer):
class ManufacturerSerializer(NetBoxModelSerializer): class ManufacturerSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
devicetype_count = serializers.IntegerField(read_only=True)
inventoryitem_count = serializers.IntegerField(read_only=True) # Related object counts
platform_count = serializers.IntegerField(read_only=True) devicetype_count = RelatedObjectCountField('dcim.devicetype', 'manufacturer')
inventoryitem_count = RelatedObjectCountField('dcim.inventoryitem', 'manufacturer')
platform_count = RelatedObjectCountField('dcim.platform', 'manufacturer')
class Meta: class Meta:
model = Manufacturer model = Manufacturer
@ -325,7 +331,6 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False, allow_null=True) subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False, allow_null=True)
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False, allow_null=True) airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False, allow_null=True)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True) weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
device_count = serializers.IntegerField(read_only=True)
# Counter fields # Counter fields
console_port_template_count = serializers.IntegerField(read_only=True) console_port_template_count = serializers.IntegerField(read_only=True)
@ -339,6 +344,9 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
module_bay_template_count = serializers.IntegerField(read_only=True) module_bay_template_count = serializers.IntegerField(read_only=True)
inventory_item_template_count = serializers.IntegerField(read_only=True) inventory_item_template_count = serializers.IntegerField(read_only=True)
# Related object counts
device_count = RelatedObjectCountField('dcim.device', 'device_type')
class Meta: class Meta:
model = DeviceType model = DeviceType
fields = [ fields = [
@ -636,8 +644,10 @@ class InventoryItemTemplateSerializer(ValidatedModelSerializer):
class DeviceRoleSerializer(NetBoxModelSerializer): class DeviceRoleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None) config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
device_count = serializers.IntegerField(read_only=True)
virtualmachine_count = serializers.IntegerField(read_only=True) # Related object counts
device_count = RelatedObjectCountField('dcim.device', 'role')
virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'role')
class Meta: class Meta:
model = DeviceRole model = DeviceRole
@ -651,8 +661,10 @@ class PlatformSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True) manufacturer = NestedManufacturerSerializer(required=False, allow_null=True)
config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None) config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
device_count = serializers.IntegerField(read_only=True)
virtualmachine_count = serializers.IntegerField(read_only=True) # Related object counts
device_count = RelatedObjectCountField('dcim.device', 'platform')
virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'platform')
class Meta: class Meta:
model = Platform model = Platform
@ -761,7 +773,7 @@ class VirtualDeviceContextSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=VirtualDeviceContextStatusChoices) status = ChoiceField(choices=VirtualDeviceContextStatusChoices)
# Related object counts # Related object counts
interface_count = serializers.IntegerField(read_only=True) interface_count = RelatedObjectCountField('dcim.interface', 'vdcs')
class Meta: class Meta:
model = VirtualDeviceContext model = VirtualDeviceContext
@ -1092,7 +1104,9 @@ class InventoryItemSerializer(NetBoxModelSerializer):
class InventoryItemRoleSerializer(NetBoxModelSerializer): class InventoryItemRoleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail')
inventoryitem_count = serializers.IntegerField(read_only=True)
# Related object counts
inventoryitem_count = RelatedObjectCountField('dcim.inventoryitem', 'role')
class Meta: class Meta:
model = InventoryItemRole model = InventoryItemRole
@ -1204,7 +1218,9 @@ class PowerPanelSerializer(NetBoxModelSerializer):
allow_null=True, allow_null=True,
default=None default=None
) )
powerfeed_count = serializers.IntegerField(read_only=True)
# Related object counts
powerfeed_count = RelatedObjectCountField('dcim.powerfeed', 'power_panel')
class Meta: class Meta:
model = PowerPanel model = PowerPanel

View File

@ -7,13 +7,11 @@ from rest_framework.response import Response
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from rest_framework.viewsets import ViewSet from rest_framework.viewsets import ViewSet
from circuits.models import Circuit
from dcim import filtersets from dcim import filtersets
from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH
from dcim.models import * from dcim.models import *
from dcim.svg import CableTraceSVG from dcim.svg import CableTraceSVG
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
from ipam.models import Prefix, VLAN
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
from netbox.api.metadata import ContentTypeMetadata from netbox.api.metadata import ContentTypeMetadata
from netbox.api.pagination import StripCountAnnotationsPaginator from netbox.api.pagination import StripCountAnnotationsPaginator
@ -22,8 +20,6 @@ from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin
from netbox.constants import NESTED_SERIALIZER_PREFIX from netbox.constants import NESTED_SERIALIZER_PREFIX
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from utilities.query_functions import CollateAsChar from utilities.query_functions import CollateAsChar
from utilities.utils import count_related
from virtualization.models import VirtualMachine
from . import serializers from . import serializers
from .exceptions import MissingFilterException from .exceptions import MissingFilterException
@ -129,14 +125,7 @@ class SiteGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
# #
class SiteViewSet(NetBoxModelViewSet): class SiteViewSet(NetBoxModelViewSet):
queryset = Site.objects.annotate( queryset = Site.objects.all()
device_count=count_related(Device, 'site'),
rack_count=count_related(Rack, 'site'),
prefix_count=count_related(Prefix, 'site'),
vlan_count=count_related(VLAN, 'site'),
circuit_count=count_related(Circuit, 'terminations__site'),
virtualmachine_count=count_related(VirtualMachine, 'cluster__site')
)
serializer_class = serializers.SiteSerializer serializer_class = serializers.SiteSerializer
filterset_class = filtersets.SiteFilterSet filterset_class = filtersets.SiteFilterSet
@ -168,9 +157,7 @@ class LocationViewSet(MPTTLockedMixin, NetBoxModelViewSet):
# #
class RackRoleViewSet(NetBoxModelViewSet): class RackRoleViewSet(NetBoxModelViewSet):
queryset = RackRole.objects.annotate( queryset = RackRole.objects.all()
rack_count=count_related(Rack, 'role')
)
serializer_class = serializers.RackRoleSerializer serializer_class = serializers.RackRoleSerializer
filterset_class = filtersets.RackRoleFilterSet filterset_class = filtersets.RackRoleFilterSet
@ -180,10 +167,7 @@ class RackRoleViewSet(NetBoxModelViewSet):
# #
class RackViewSet(NetBoxModelViewSet): class RackViewSet(NetBoxModelViewSet):
queryset = Rack.objects.annotate( queryset = Rack.objects.all()
device_count=count_related(Device, 'rack'),
powerfeed_count=count_related(PowerFeed, 'rack')
)
serializer_class = serializers.RackSerializer serializer_class = serializers.RackSerializer
filterset_class = filtersets.RackFilterSet filterset_class = filtersets.RackFilterSet
@ -255,11 +239,7 @@ class RackReservationViewSet(NetBoxModelViewSet):
# #
class ManufacturerViewSet(NetBoxModelViewSet): class ManufacturerViewSet(NetBoxModelViewSet):
queryset = Manufacturer.objects.annotate( queryset = Manufacturer.objects.all()
devicetype_count=count_related(DeviceType, 'manufacturer'),
inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
platform_count=count_related(Platform, 'manufacturer')
)
serializer_class = serializers.ManufacturerSerializer serializer_class = serializers.ManufacturerSerializer
filterset_class = filtersets.ManufacturerFilterSet filterset_class = filtersets.ManufacturerFilterSet
@ -269,9 +249,7 @@ class ManufacturerViewSet(NetBoxModelViewSet):
# #
class DeviceTypeViewSet(NetBoxModelViewSet): class DeviceTypeViewSet(NetBoxModelViewSet):
queryset = DeviceType.objects.annotate( queryset = DeviceType.objects.all()
device_count=count_related(Device, 'device_type')
)
serializer_class = serializers.DeviceTypeSerializer serializer_class = serializers.DeviceTypeSerializer
filterset_class = filtersets.DeviceTypeFilterSet filterset_class = filtersets.DeviceTypeFilterSet
@ -351,10 +329,7 @@ class InventoryItemTemplateViewSet(MPTTLockedMixin, NetBoxModelViewSet):
# #
class DeviceRoleViewSet(NetBoxModelViewSet): class DeviceRoleViewSet(NetBoxModelViewSet):
queryset = DeviceRole.objects.annotate( queryset = DeviceRole.objects.all()
device_count=count_related(Device, 'role'),
virtualmachine_count=count_related(VirtualMachine, 'role')
)
serializer_class = serializers.DeviceRoleSerializer serializer_class = serializers.DeviceRoleSerializer
filterset_class = filtersets.DeviceRoleFilterSet filterset_class = filtersets.DeviceRoleFilterSet
@ -364,10 +339,7 @@ class DeviceRoleViewSet(NetBoxModelViewSet):
# #
class PlatformViewSet(NetBoxModelViewSet): class PlatformViewSet(NetBoxModelViewSet):
queryset = Platform.objects.annotate( queryset = Platform.objects.all()
device_count=count_related(Device, 'platform'),
virtualmachine_count=count_related(VirtualMachine, 'platform')
)
serializer_class = serializers.PlatformSerializer serializer_class = serializers.PlatformSerializer
filterset_class = filtersets.PlatformFilterSet filterset_class = filtersets.PlatformFilterSet
@ -410,9 +382,7 @@ class DeviceViewSet(
class VirtualDeviceContextViewSet(NetBoxModelViewSet): class VirtualDeviceContextViewSet(NetBoxModelViewSet):
queryset = VirtualDeviceContext.objects.annotate( queryset = VirtualDeviceContext.objects.all()
interface_count=count_related(Interface, 'vdcs'),
)
serializer_class = serializers.VirtualDeviceContextSerializer serializer_class = serializers.VirtualDeviceContextSerializer
filterset_class = filtersets.VirtualDeviceContextFilterSet filterset_class = filtersets.VirtualDeviceContextFilterSet
@ -513,9 +483,7 @@ class InventoryItemViewSet(MPTTLockedMixin, NetBoxModelViewSet):
# #
class InventoryItemRoleViewSet(NetBoxModelViewSet): class InventoryItemRoleViewSet(NetBoxModelViewSet):
queryset = InventoryItemRole.objects.annotate( queryset = InventoryItemRole.objects.all()
inventoryitem_count=count_related(InventoryItem, 'role')
)
serializer_class = serializers.InventoryItemRoleSerializer serializer_class = serializers.InventoryItemRoleSerializer
filterset_class = filtersets.InventoryItemRoleFilterSet filterset_class = filtersets.InventoryItemRoleFilterSet
@ -552,9 +520,7 @@ class VirtualChassisViewSet(NetBoxModelViewSet):
# #
class PowerPanelViewSet(NetBoxModelViewSet): class PowerPanelViewSet(NetBoxModelViewSet):
queryset = PowerPanel.objects.annotate( queryset = PowerPanel.objects.all()
powerfeed_count=count_related(PowerFeed, 'power_panel')
)
serializer_class = serializers.PowerPanelSerializer serializer_class = serializers.PowerPanelSerializer
filterset_class = filtersets.PowerPanelFilterSet filterset_class = filtersets.PowerPanelFilterSet

View File

@ -3,7 +3,6 @@ from django.core.exceptions import ObjectDoesNotExist
from drf_spectacular.types import OpenApiTypes from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import ListField
from core.api.nested_serializers import NestedDataSourceSerializer, NestedDataFileSerializer, NestedJobSerializer from core.api.nested_serializers import NestedDataSourceSerializer, NestedDataFileSerializer, NestedJobSerializer
from core.api.serializers import JobSerializer from core.api.serializers import JobSerializer
@ -16,7 +15,7 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
from netbox.api.exceptions import SerializerNotFound from netbox.api.exceptions import SerializerNotFound
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer
from netbox.api.serializers.features import TaggableModelSerializer from netbox.api.serializers.features import TaggableModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX from netbox.constants import NESTED_SERIALIZER_PREFIX
@ -290,6 +289,9 @@ class TagSerializer(ValidatedModelSerializer):
) )
tagged_items = serializers.IntegerField(read_only=True) tagged_items = serializers.IntegerField(read_only=True)
# Related object counts
tagged_items = RelatedObjectCountField('extras.taggeditem', 'tag')
class Meta: class Meta:
model = Tag model = Tag
fields = [ fields = [

View File

@ -23,7 +23,7 @@ from netbox.api.metadata import ContentTypeMetadata
from netbox.api.renderers import TextRenderer from netbox.api.renderers import TextRenderer
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from utilities.exceptions import RQWorkerNotRunningException from utilities.exceptions import RQWorkerNotRunningException
from utilities.utils import copy_safe_request, count_related from utilities.utils import copy_safe_request
from . import serializers from . import serializers
from .mixins import ConfigTemplateRenderMixin from .mixins import ConfigTemplateRenderMixin
@ -147,9 +147,7 @@ class BookmarkViewSet(NetBoxModelViewSet):
# #
class TagViewSet(NetBoxModelViewSet): class TagViewSet(NetBoxModelViewSet):
queryset = Tag.objects.annotate( queryset = Tag.objects.all()
tagged_items=count_related(TaggedItem, 'tag')
)
serializer_class = serializers.TagSerializer serializer_class = serializers.TagSerializer
filterset_class = filtersets.TagFilterSet filterset_class = filtersets.TagFilterSet

View File

@ -2,6 +2,7 @@ from drf_spectacular.utils import extend_schema_serializer
from rest_framework import serializers from rest_framework import serializers
from ipam import models from ipam import models
from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import WritableNestedSerializer from netbox.api.serializers import WritableNestedSerializer
from .field_serializers import IPAddressField from .field_serializers import IPAddressField
@ -58,7 +59,7 @@ class NestedASNSerializer(WritableNestedSerializer):
) )
class NestedVRFSerializer(WritableNestedSerializer): class NestedVRFSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
prefix_count = serializers.IntegerField(read_only=True) prefix_count = RelatedObjectCountField('ipam.prefix', 'vrf')
class Meta: class Meta:
model = models.VRF model = models.VRF
@ -86,7 +87,7 @@ class NestedRouteTargetSerializer(WritableNestedSerializer):
) )
class NestedRIRSerializer(WritableNestedSerializer): class NestedRIRSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
aggregate_count = serializers.IntegerField(read_only=True) aggregate_count = RelatedObjectCountField('ipam.aggregate', 'rir')
class Meta: class Meta:
model = models.RIR model = models.RIR
@ -132,8 +133,8 @@ class NestedFHRPGroupAssignmentSerializer(WritableNestedSerializer):
) )
class NestedRoleSerializer(WritableNestedSerializer): class NestedRoleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail')
prefix_count = serializers.IntegerField(read_only=True) prefix_count = RelatedObjectCountField('ipam.prefix', 'role')
vlan_count = serializers.IntegerField(read_only=True) vlan_count = RelatedObjectCountField('ipam.vlan', 'role')
class Meta: class Meta:
model = models.Role model = models.Role
@ -145,7 +146,7 @@ class NestedRoleSerializer(WritableNestedSerializer):
) )
class NestedVLANGroupSerializer(WritableNestedSerializer): class NestedVLANGroupSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlangroup-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlangroup-detail')
vlan_count = serializers.IntegerField(read_only=True) vlan_count = RelatedObjectCountField('ipam.vlan', 'group')
class Meta: class Meta:
model = models.VLANGroup model = models.VLANGroup

View File

@ -6,7 +6,7 @@ from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerial
from ipam.choices import * from ipam.choices import *
from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS, VLANGROUP_SCOPE_TYPES from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS, VLANGROUP_SCOPE_TYPES
from ipam.models import * from ipam.models import *
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX from netbox.constants import NESTED_SERIALIZER_PREFIX
from tenancy.api.nested_serializers import NestedTenantSerializer from tenancy.api.nested_serializers import NestedTenantSerializer
@ -43,8 +43,10 @@ class ASNSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
rir = NestedRIRSerializer(required=False, allow_null=True) rir = NestedRIRSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True)
site_count = serializers.IntegerField(read_only=True)
provider_count = serializers.IntegerField(read_only=True) # Related object counts
site_count = RelatedObjectCountField('dcim.site', 'asns')
provider_count = RelatedObjectCountField('circuits.provider', 'asns')
class Meta: class Meta:
model = ASN model = ASN
@ -90,8 +92,10 @@ class VRFSerializer(NetBoxModelSerializer):
required=False, required=False,
many=True many=True
) )
ipaddress_count = serializers.IntegerField(read_only=True)
prefix_count = serializers.IntegerField(read_only=True) # Related object counts
ipaddress_count = RelatedObjectCountField('ipam.ipaddress', 'vrf')
prefix_count = RelatedObjectCountField('ipam.prefix', 'vrf')
class Meta: class Meta:
model = VRF model = VRF
@ -124,7 +128,9 @@ class RouteTargetSerializer(NetBoxModelSerializer):
class RIRSerializer(NetBoxModelSerializer): class RIRSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
aggregate_count = serializers.IntegerField(read_only=True)
# Related object counts
aggregate_count = RelatedObjectCountField('ipam.aggregate', 'rir')
class Meta: class Meta:
model = RIR model = RIR
@ -195,8 +201,10 @@ class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
class RoleSerializer(NetBoxModelSerializer): class RoleSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail') url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail')
prefix_count = serializers.IntegerField(read_only=True)
vlan_count = serializers.IntegerField(read_only=True) # Related object counts
prefix_count = RelatedObjectCountField('ipam.prefix', 'role')
vlan_count = RelatedObjectCountField('ipam.vlan', 'role')
class Meta: class Meta:
model = Role model = Role
@ -218,9 +226,11 @@ class VLANGroupSerializer(NetBoxModelSerializer):
) )
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
scope = serializers.SerializerMethodField(read_only=True) scope = serializers.SerializerMethodField(read_only=True)
vlan_count = serializers.IntegerField(read_only=True)
utilization = serializers.CharField(read_only=True) utilization = serializers.CharField(read_only=True)
# Related object counts
vlan_count = RelatedObjectCountField('ipam.vlan', 'group')
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = [ fields = [
@ -247,7 +257,9 @@ class VLANSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=VLANStatusChoices, required=False) status = ChoiceField(choices=VLANStatusChoices, required=False)
role = NestedRoleSerializer(required=False, allow_null=True) role = NestedRoleSerializer(required=False, allow_null=True)
l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True, allow_null=True) l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True, allow_null=True)
prefix_count = serializers.IntegerField(read_only=True)
# Related object counts
prefix_count = RelatedObjectCountField('ipam.prefix', 'vlan')
class Meta: class Meta:
model = VLAN model = VLAN

View File

@ -12,8 +12,6 @@ from rest_framework.response import Response
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from rest_framework.views import APIView from rest_framework.views import APIView
from circuits.models import Provider
from dcim.models import Site
from ipam import filtersets from ipam import filtersets
from ipam.models import * from ipam.models import *
from ipam.utils import get_next_available_prefix from ipam.utils import get_next_available_prefix
@ -22,7 +20,6 @@ from netbox.api.viewsets.mixins import ObjectValidationMixin
from netbox.config import get_config from netbox.config import get_config
from netbox.constants import ADVISORY_LOCK_KEYS from netbox.constants import ADVISORY_LOCK_KEYS
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from utilities.utils import count_related
from . import serializers from . import serializers
@ -45,19 +42,13 @@ class ASNRangeViewSet(NetBoxModelViewSet):
class ASNViewSet(NetBoxModelViewSet): class ASNViewSet(NetBoxModelViewSet):
queryset = ASN.objects.annotate( queryset = ASN.objects.all()
site_count=count_related(Site, 'asns'),
provider_count=count_related(Provider, 'asns')
)
serializer_class = serializers.ASNSerializer serializer_class = serializers.ASNSerializer
filterset_class = filtersets.ASNFilterSet filterset_class = filtersets.ASNFilterSet
class VRFViewSet(NetBoxModelViewSet): class VRFViewSet(NetBoxModelViewSet):
queryset = VRF.objects.annotate( queryset = VRF.objects.all()
ipaddress_count=count_related(IPAddress, 'vrf'),
prefix_count=count_related(Prefix, 'vrf')
)
serializer_class = serializers.VRFSerializer serializer_class = serializers.VRFSerializer
filterset_class = filtersets.VRFFilterSet filterset_class = filtersets.VRFFilterSet
@ -69,9 +60,7 @@ class RouteTargetViewSet(NetBoxModelViewSet):
class RIRViewSet(NetBoxModelViewSet): class RIRViewSet(NetBoxModelViewSet):
queryset = RIR.objects.annotate( queryset = RIR.objects.all()
aggregate_count=count_related(Aggregate, 'rir')
)
serializer_class = serializers.RIRSerializer serializer_class = serializers.RIRSerializer
filterset_class = filtersets.RIRFilterSet filterset_class = filtersets.RIRFilterSet
@ -83,10 +72,7 @@ class AggregateViewSet(NetBoxModelViewSet):
class RoleViewSet(NetBoxModelViewSet): class RoleViewSet(NetBoxModelViewSet):
queryset = Role.objects.annotate( queryset = Role.objects.all()
prefix_count=count_related(Prefix, 'role'),
vlan_count=count_related(VLAN, 'role')
)
serializer_class = serializers.RoleSerializer serializer_class = serializers.RoleSerializer
filterset_class = filtersets.RoleFilterSet filterset_class = filtersets.RoleFilterSet
@ -151,8 +137,6 @@ class VLANGroupViewSet(NetBoxModelViewSet):
class VLANViewSet(NetBoxModelViewSet): class VLANViewSet(NetBoxModelViewSet):
queryset = VLAN.objects.prefetch_related( queryset = VLAN.objects.prefetch_related(
'l2vpn_terminations', # Referenced by VLANSerializer.l2vpn_termination 'l2vpn_terminations', # Referenced by VLANSerializer.l2vpn_termination
).annotate(
prefix_count=count_related(Prefix, 'vlan')
) )
serializer_class = serializers.VLANSerializer serializer_class = serializers.VLANSerializer
filterset_class = filtersets.VLANFilterSet filterset_class = filtersets.VLANFilterSet

View File

@ -3,7 +3,7 @@ from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers from rest_framework import serializers
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX from netbox.constants import NESTED_SERIALIZER_PREFIX
from tenancy.choices import ContactPriorityChoices from tenancy.choices import ContactPriorityChoices
@ -32,16 +32,18 @@ class TenantGroupSerializer(NestedGroupModelSerializer):
class TenantSerializer(NetBoxModelSerializer): class TenantSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail') url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
group = NestedTenantGroupSerializer(required=False, allow_null=True) group = NestedTenantGroupSerializer(required=False, allow_null=True)
circuit_count = serializers.IntegerField(read_only=True)
device_count = serializers.IntegerField(read_only=True) # Related object counts
ipaddress_count = serializers.IntegerField(read_only=True) circuit_count = RelatedObjectCountField('circuits.circuit', 'tenant')
prefix_count = serializers.IntegerField(read_only=True) device_count = RelatedObjectCountField('dcim.device', 'tenant')
rack_count = serializers.IntegerField(read_only=True) rack_count = RelatedObjectCountField('dcim.rack', 'tenant')
site_count = serializers.IntegerField(read_only=True) site_count = RelatedObjectCountField('dcim.site', 'tenant')
virtualmachine_count = serializers.IntegerField(read_only=True) ipaddress_count = RelatedObjectCountField('ipam.ipaddress', 'tenant')
vlan_count = serializers.IntegerField(read_only=True) prefix_count = RelatedObjectCountField('ipam.prefix', 'tenant')
vrf_count = serializers.IntegerField(read_only=True) vlan_count = RelatedObjectCountField('ipam.vlan', 'tenant')
cluster_count = serializers.IntegerField(read_only=True) vrf_count = RelatedObjectCountField('ipam.vrf', 'tenant')
virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'tenant')
cluster_count = RelatedObjectCountField('virtualization.cluster', 'tenant')
class Meta: class Meta:
model = Tenant model = Tenant

View File

@ -1,13 +1,8 @@
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from circuits.models import Circuit
from dcim.models import Device, Rack, Site
from ipam.models import IPAddress, Prefix, VLAN, VRF
from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin
from tenancy import filtersets from tenancy import filtersets
from tenancy.models import * from tenancy.models import *
from utilities.utils import count_related
from virtualization.models import VirtualMachine, Cluster
from . import serializers from . import serializers
@ -36,18 +31,7 @@ class TenantGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
class TenantViewSet(NetBoxModelViewSet): class TenantViewSet(NetBoxModelViewSet):
queryset = Tenant.objects.annotate( queryset = Tenant.objects.all()
circuit_count=count_related(Circuit, 'tenant'),
device_count=count_related(Device, 'tenant'),
ipaddress_count=count_related(IPAddress, 'tenant'),
prefix_count=count_related(Prefix, 'tenant'),
rack_count=count_related(Rack, 'tenant'),
site_count=count_related(Site, 'tenant'),
virtualmachine_count=count_related(VirtualMachine, 'tenant'),
vlan_count=count_related(VLAN, 'tenant'),
vrf_count=count_related(VRF, 'tenant'),
cluster_count=count_related(Cluster, 'tenant')
)
serializer_class = serializers.TenantSerializer serializer_class = serializers.TenantSerializer
filterset_class = filtersets.TenantFilterSet filterset_class = filtersets.TenantFilterSet

View File

@ -1,6 +1,7 @@
from drf_spectacular.utils import extend_schema_serializer from drf_spectacular.utils import extend_schema_serializer
from rest_framework import serializers from rest_framework import serializers
from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import WritableNestedSerializer from netbox.api.serializers import WritableNestedSerializer
from virtualization.models import * from virtualization.models import *
@ -23,7 +24,7 @@ __all__ = [
) )
class NestedClusterTypeSerializer(WritableNestedSerializer): class NestedClusterTypeSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail')
cluster_count = serializers.IntegerField(read_only=True) cluster_count = RelatedObjectCountField('virtualization.cluster', 'type')
class Meta: class Meta:
model = ClusterType model = ClusterType
@ -35,7 +36,7 @@ class NestedClusterTypeSerializer(WritableNestedSerializer):
) )
class NestedClusterGroupSerializer(WritableNestedSerializer): class NestedClusterGroupSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail')
cluster_count = serializers.IntegerField(read_only=True) cluster_count = RelatedObjectCountField('virtualization.cluster', 'group')
class Meta: class Meta:
model = ClusterGroup model = ClusterGroup
@ -47,7 +48,7 @@ class NestedClusterGroupSerializer(WritableNestedSerializer):
) )
class NestedClusterSerializer(WritableNestedSerializer): class NestedClusterSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
virtualmachine_count = serializers.IntegerField(read_only=True) virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'cluster')
class Meta: class Meta:
model = Cluster model = Cluster

View File

@ -8,7 +8,7 @@ from dcim.choices import InterfaceModeChoices
from extras.api.nested_serializers import NestedConfigTemplateSerializer from extras.api.nested_serializers import NestedConfigTemplateSerializer
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
from ipam.models import VLAN from ipam.models import VLAN
from netbox.api.fields import ChoiceField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from tenancy.api.nested_serializers import NestedTenantSerializer from tenancy.api.nested_serializers import NestedTenantSerializer
from virtualization.choices import * from virtualization.choices import *
@ -23,7 +23,9 @@ from .nested_serializers import *
class ClusterTypeSerializer(NetBoxModelSerializer): class ClusterTypeSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail')
cluster_count = serializers.IntegerField(read_only=True)
# Related object counts
cluster_count = RelatedObjectCountField('virtualization.cluster', 'type')
class Meta: class Meta:
model = ClusterType model = ClusterType
@ -35,7 +37,9 @@ class ClusterTypeSerializer(NetBoxModelSerializer):
class ClusterGroupSerializer(NetBoxModelSerializer): class ClusterGroupSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail')
cluster_count = serializers.IntegerField(read_only=True)
# Related object counts
cluster_count = RelatedObjectCountField('virtualization.cluster', 'group')
class Meta: class Meta:
model = ClusterGroup model = ClusterGroup
@ -52,8 +56,10 @@ class ClusterSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=ClusterStatusChoices, required=False) status = ChoiceField(choices=ClusterStatusChoices, required=False)
tenant = NestedTenantSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True)
site = NestedSiteSerializer(required=False, allow_null=True, default=None) site = NestedSiteSerializer(required=False, allow_null=True, default=None)
device_count = serializers.IntegerField(read_only=True)
virtualmachine_count = serializers.IntegerField(read_only=True) # Related object counts
device_count = RelatedObjectCountField('dcim.device', 'cluster')
virtualmachine_count = RelatedObjectCountField('virtualization.virtualmachine', 'cluster')
class Meta: class Meta:
model = Cluster model = Cluster

View File

@ -1,10 +1,8 @@
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from dcim.models import Device
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from utilities.query_functions import CollateAsChar from utilities.query_functions import CollateAsChar
from utilities.utils import count_related
from virtualization import filtersets from virtualization import filtersets
from virtualization.models import * from virtualization.models import *
from . import serializers from . import serializers
@ -23,26 +21,19 @@ class VirtualizationRootView(APIRootView):
# #
class ClusterTypeViewSet(NetBoxModelViewSet): class ClusterTypeViewSet(NetBoxModelViewSet):
queryset = ClusterType.objects.annotate( queryset = ClusterType.objects.all()
cluster_count=count_related(Cluster, 'type')
)
serializer_class = serializers.ClusterTypeSerializer serializer_class = serializers.ClusterTypeSerializer
filterset_class = filtersets.ClusterTypeFilterSet filterset_class = filtersets.ClusterTypeFilterSet
class ClusterGroupViewSet(NetBoxModelViewSet): class ClusterGroupViewSet(NetBoxModelViewSet):
queryset = ClusterGroup.objects.annotate( queryset = ClusterGroup.objects.all()
cluster_count=count_related(Cluster, 'group')
)
serializer_class = serializers.ClusterGroupSerializer serializer_class = serializers.ClusterGroupSerializer
filterset_class = filtersets.ClusterGroupFilterSet filterset_class = filtersets.ClusterGroupFilterSet
class ClusterViewSet(NetBoxModelViewSet): class ClusterViewSet(NetBoxModelViewSet):
queryset = Cluster.objects.annotate( queryset = Cluster.objects.all()
device_count=count_related(Device, 'cluster'),
virtualmachine_count=count_related(VirtualMachine, 'cluster')
)
serializer_class = serializers.ClusterSerializer serializer_class = serializers.ClusterSerializer
filterset_class = filtersets.ClusterFilterSet filterset_class = filtersets.ClusterFilterSet

View File

@ -1,6 +1,7 @@
from drf_spectacular.utils import extend_schema_serializer from drf_spectacular.utils import extend_schema_serializer
from rest_framework import serializers from rest_framework import serializers
from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import WritableNestedSerializer from netbox.api.serializers import WritableNestedSerializer
from vpn import models from vpn import models
@ -23,7 +24,7 @@ __all__ = (
) )
class NestedTunnelGroupSerializer(WritableNestedSerializer): class NestedTunnelGroupSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail') url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
tunnel_count = serializers.IntegerField(read_only=True) tunnel_count = RelatedObjectCountField('vpn.tunnel', 'group')
class Meta: class Meta:
model = models.TunnelGroup model = models.TunnelGroup

View File

@ -4,7 +4,7 @@ from rest_framework import serializers
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedRouteTargetSerializer from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedRouteTargetSerializer
from ipam.models import RouteTarget from ipam.models import RouteTarget
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX from netbox.constants import NESTED_SERIALIZER_PREFIX
from tenancy.api.nested_serializers import NestedTenantSerializer from tenancy.api.nested_serializers import NestedTenantSerializer
@ -29,7 +29,9 @@ __all__ = (
class TunnelGroupSerializer(NetBoxModelSerializer): class TunnelGroupSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail') url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
tunnel_count = serializers.IntegerField(read_only=True)
# Related object counts
tunnel_count = RelatedObjectCountField('vpn.tunnel', 'group')
class Meta: class Meta:
model = TunnelGroup model = TunnelGroup
@ -59,11 +61,14 @@ class TunnelSerializer(NetBoxModelSerializer):
allow_null=True allow_null=True
) )
# Related object counts
terminations_count = RelatedObjectCountField('vpn.tunneltermination', 'tunnel')
class Meta: class Meta:
model = Tunnel model = Tunnel
fields = ( fields = (
'id', 'url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id', 'id', 'url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id',
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'terminations_count',
) )

View File

@ -1,7 +1,6 @@
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets import NetBoxModelViewSet
from utilities.utils import count_related
from vpn import filtersets from vpn import filtersets
from vpn.models import * from vpn.models import *
from . import serializers from . import serializers
@ -34,17 +33,13 @@ class VPNRootView(APIRootView):
# #
class TunnelGroupViewSet(NetBoxModelViewSet): class TunnelGroupViewSet(NetBoxModelViewSet):
queryset = TunnelGroup.objects.annotate( queryset = TunnelGroup.objects.all()
tunnel_count=count_related(Tunnel, 'group')
)
serializer_class = serializers.TunnelGroupSerializer serializer_class = serializers.TunnelGroupSerializer
filterset_class = filtersets.TunnelGroupFilterSet filterset_class = filtersets.TunnelGroupFilterSet
class TunnelViewSet(NetBoxModelViewSet): class TunnelViewSet(NetBoxModelViewSet):
queryset = Tunnel.objects.annotate( queryset = Tunnel.objects.all()
terminations_count=count_related(TunnelTermination, 'tunnel')
)
serializer_class = serializers.TunnelSerializer serializer_class = serializers.TunnelSerializer
filterset_class = filtersets.TunnelFilterSet filterset_class = filtersets.TunnelFilterSet