mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Added child counts to API serializers (WIP)
This commit is contained in:
@ -63,6 +63,8 @@ to now use "Extras | Tag."
|
|||||||
|
|
||||||
* dcim.Interface: `form_factor` has been renamed to `type`. Backward-compatibile support for `form_factor` will be maintained until NetBox v2.7.
|
* dcim.Interface: `form_factor` has been renamed to `type`. Backward-compatibile support 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.DeviceType: `instance_count` has been renamed to `device_count`.
|
||||||
|
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
||||||
|
@ -17,10 +17,11 @@ __all__ = [
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'circuit_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -29,10 +30,11 @@ class NestedProviderSerializer(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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'circuit_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedCircuitSerializer(WritableNestedSerializer):
|
class NestedCircuitSerializer(WritableNestedSerializer):
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
|
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
|
||||||
|
|
||||||
from circuits.constants import CIRCUIT_STATUS_CHOICES
|
from circuits.constants import CIRCUIT_STATUS_CHOICES
|
||||||
@ -16,12 +17,13 @@ from .nested_serializers import *
|
|||||||
|
|
||||||
class ProviderSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class ProviderSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
circuit_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags',
|
'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags',
|
||||||
'custom_fields', 'created', 'last_updated',
|
'custom_fields', 'created', 'last_updated', 'circuit_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -30,10 +32,11 @@ class ProviderSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class CircuitTypeSerializer(ValidatedModelSerializer):
|
class CircuitTypeSerializer(ValidatedModelSerializer):
|
||||||
|
circuit_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'circuit_count']
|
||||||
|
|
||||||
|
|
||||||
class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from django.db.models import Count
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -27,7 +28,9 @@ class CircuitsFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ProviderViewSet(CustomFieldModelViewSet):
|
class ProviderViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Provider.objects.prefetch_related('tags')
|
queryset = Provider.objects.prefetch_related('tags').annotate(
|
||||||
|
circuit_count=Count('circuits')
|
||||||
|
)
|
||||||
serializer_class = serializers.ProviderSerializer
|
serializer_class = serializers.ProviderSerializer
|
||||||
filterset_class = filters.ProviderFilter
|
filterset_class = filters.ProviderFilter
|
||||||
|
|
||||||
@ -47,7 +50,9 @@ class ProviderViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class CircuitTypeViewSet(ModelViewSet):
|
class CircuitTypeViewSet(ModelViewSet):
|
||||||
queryset = CircuitType.objects.all()
|
queryset = CircuitType.objects.annotate(
|
||||||
|
circuit_count=Count('circuits')
|
||||||
|
)
|
||||||
serializer_class = serializers.CircuitTypeSerializer
|
serializer_class = serializers.CircuitTypeSerializer
|
||||||
filterset_class = filters.CircuitTypeFilter
|
filterset_class = filters.CircuitTypeFilter
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class ProviderTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['circuit_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_provider(self):
|
def test_create_provider(self):
|
||||||
@ -162,7 +162,7 @@ class CircuitTypeTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['circuit_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_circuittype(self):
|
def test_create_circuittype(self):
|
||||||
|
@ -42,10 +42,11 @@ __all__ = [
|
|||||||
|
|
||||||
class NestedRegionSerializer(WritableNestedSerializer):
|
class NestedRegionSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
||||||
|
site_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'site_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedSiteSerializer(WritableNestedSerializer):
|
class NestedSiteSerializer(WritableNestedSerializer):
|
||||||
@ -62,26 +63,29 @@ class NestedSiteSerializer(WritableNestedSerializer):
|
|||||||
|
|
||||||
class NestedRackGroupSerializer(WritableNestedSerializer):
|
class NestedRackGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
|
||||||
|
rack_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackGroup
|
model = RackGroup
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'rack_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'rack_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ['id', 'url', 'name', 'display_name']
|
fields = ['id', 'url', 'name', 'display_name', 'device_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -90,19 +94,21 @@ class NestedRackSerializer(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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'devicetype_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = ['id', 'url', 'manufacturer', 'model', 'slug', 'display_name']
|
fields = ['id', 'url', 'manufacturer', 'model', 'slug', 'display_name', 'device_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedRearPortTemplateSerializer(WritableNestedSerializer):
|
class NestedRearPortTemplateSerializer(WritableNestedSerializer):
|
||||||
@ -127,18 +133,22 @@ class NestedFrontPortTemplateSerializer(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)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'device_count', 'virtualmachine_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'device_count', 'virtualmachine_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedDeviceSerializer(WritableNestedSerializer):
|
class NestedDeviceSerializer(WritableNestedSerializer):
|
||||||
@ -245,10 +255,11 @@ class NestedCableSerializer(serializers.ModelSerializer):
|
|||||||
class NestedVirtualChassisSerializer(WritableNestedSerializer):
|
class NestedVirtualChassisSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
|
||||||
master = NestedDeviceSerializer()
|
master = NestedDeviceSerializer()
|
||||||
|
member_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ['id', 'url', 'master']
|
fields = ['id', 'url', 'master', 'member_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -257,10 +268,11 @@ 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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = ['id', 'url', 'name']
|
fields = ['id', 'url', 'name', 'powerfeed_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedPowerFeedSerializer(WritableNestedSerializer):
|
class NestedPowerFeedSerializer(WritableNestedSerializer):
|
||||||
|
@ -59,10 +59,11 @@ class ConnectedEndpointSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
class RegionSerializer(serializers.ModelSerializer):
|
class RegionSerializer(serializers.ModelSerializer):
|
||||||
parent = NestedRegionSerializer(required=False, allow_null=True)
|
parent = NestedRegionSerializer(required=False, allow_null=True)
|
||||||
|
site_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
fields = ['id', 'name', 'slug', 'parent']
|
fields = ['id', 'name', 'slug', 'parent', 'site_count']
|
||||||
|
|
||||||
|
|
||||||
class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
@ -93,17 +94,19 @@ class SiteSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
|
|
||||||
class RackGroupSerializer(ValidatedModelSerializer):
|
class RackGroupSerializer(ValidatedModelSerializer):
|
||||||
site = NestedSiteSerializer()
|
site = NestedSiteSerializer()
|
||||||
|
rack_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackGroup
|
model = RackGroup
|
||||||
fields = ['id', 'name', 'slug', 'site']
|
fields = ['id', 'name', 'slug', 'site', 'rack_count']
|
||||||
|
|
||||||
|
|
||||||
class RackRoleSerializer(ValidatedModelSerializer):
|
class RackRoleSerializer(ValidatedModelSerializer):
|
||||||
|
rack_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
fields = ['id', 'name', 'slug', 'color']
|
fields = ['id', 'name', 'slug', 'color', 'rack_count']
|
||||||
|
|
||||||
|
|
||||||
class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
@ -116,13 +119,14 @@ class RackSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
width = ChoiceField(choices=RACK_WIDTH_CHOICES, required=False)
|
width = ChoiceField(choices=RACK_WIDTH_CHOICES, required=False)
|
||||||
outer_unit = ChoiceField(choices=RACK_DIMENSION_UNIT_CHOICES, required=False)
|
outer_unit = ChoiceField(choices=RACK_DIMENSION_UNIT_CHOICES, required=False)
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial',
|
'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial',
|
||||||
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
||||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||||
]
|
]
|
||||||
# Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This
|
# Omit the UniqueTogetherValidator that would be automatically added to validate (group, facility_id). This
|
||||||
# prevents facility_id from being interpreted as a required field.
|
# prevents facility_id from being interpreted as a required field.
|
||||||
@ -169,23 +173,24 @@ class RackReservationSerializer(ValidatedModelSerializer):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ManufacturerSerializer(ValidatedModelSerializer):
|
class ManufacturerSerializer(ValidatedModelSerializer):
|
||||||
|
devicetype_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'devicetype_count']
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class DeviceTypeSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
manufacturer = NestedManufacturerSerializer()
|
manufacturer = NestedManufacturerSerializer()
|
||||||
subdevice_role = ChoiceField(choices=SUBDEVICE_ROLE_CHOICES, required=False, allow_null=True)
|
subdevice_role = ChoiceField(choices=SUBDEVICE_ROLE_CHOICES, required=False, allow_null=True)
|
||||||
instance_count = serializers.IntegerField(source='instances.count', read_only=True)
|
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'manufacturer', 'model', 'slug', 'display_name', 'part_number', 'u_height', 'is_full_depth',
|
'id', 'manufacturer', 'model', 'slug', 'display_name', 'part_number', 'u_height', 'is_full_depth',
|
||||||
'subdevice_role', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'instance_count',
|
'subdevice_role', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -272,18 +277,25 @@ class DeviceBayTemplateSerializer(ValidatedModelSerializer):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class DeviceRoleSerializer(ValidatedModelSerializer):
|
class DeviceRoleSerializer(ValidatedModelSerializer):
|
||||||
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
fields = ['id', 'name', 'slug', 'color', 'vm_role']
|
fields = ['id', 'name', 'slug', 'color', 'vm_role', 'device_count', 'virtualmachine_count']
|
||||||
|
|
||||||
|
|
||||||
class PlatformSerializer(ValidatedModelSerializer):
|
class PlatformSerializer(ValidatedModelSerializer):
|
||||||
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True)
|
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True)
|
||||||
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = ['id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args']
|
fields = [
|
||||||
|
'id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'device_count',
|
||||||
|
'virtualmachine_count',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class DeviceSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
@ -613,17 +625,17 @@ class InterfaceConnectionSerializer(ValidatedModelSerializer):
|
|||||||
class VirtualChassisSerializer(TaggitSerializer, ValidatedModelSerializer):
|
class VirtualChassisSerializer(TaggitSerializer, ValidatedModelSerializer):
|
||||||
master = NestedDeviceSerializer()
|
master = NestedDeviceSerializer()
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
member_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ['id', 'master', 'domain', 'tags']
|
fields = ['id', 'master', 'domain', 'tags', 'member_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Power panels
|
# Power panels
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class PowerPanelSerializer(ValidatedModelSerializer):
|
class PowerPanelSerializer(ValidatedModelSerializer):
|
||||||
site = NestedSiteSerializer()
|
site = NestedSiteSerializer()
|
||||||
rack_group = NestedRackGroupSerializer(
|
rack_group = NestedRackGroupSerializer(
|
||||||
@ -631,10 +643,11 @@ class PowerPanelSerializer(ValidatedModelSerializer):
|
|||||||
allow_null=True,
|
allow_null=True,
|
||||||
default=None
|
default=None
|
||||||
)
|
)
|
||||||
|
powerfeed_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = ['id', 'site', 'rack_group', 'name']
|
fields = ['id', 'site', 'rack_group', 'name', 'powerfeed_count']
|
||||||
|
|
||||||
|
|
||||||
class PowerFeedSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class PowerFeedSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import F
|
from django.db.models import Count, F
|
||||||
from django.http import HttpResponseForbidden
|
from django.http import HttpResponseForbidden
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
@ -93,7 +93,9 @@ class CableTraceMixin(object):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RegionViewSet(ModelViewSet):
|
class RegionViewSet(ModelViewSet):
|
||||||
queryset = Region.objects.all()
|
queryset = Region.objects.annotate(
|
||||||
|
site_count=Count('sites')
|
||||||
|
)
|
||||||
serializer_class = serializers.RegionSerializer
|
serializer_class = serializers.RegionSerializer
|
||||||
filterset_class = filters.RegionFilter
|
filterset_class = filters.RegionFilter
|
||||||
|
|
||||||
@ -123,7 +125,9 @@ class SiteViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackGroupViewSet(ModelViewSet):
|
class RackGroupViewSet(ModelViewSet):
|
||||||
queryset = RackGroup.objects.select_related('site')
|
queryset = RackGroup.objects.select_related('site').annotate(
|
||||||
|
rack_count=Count('racks')
|
||||||
|
)
|
||||||
serializer_class = serializers.RackGroupSerializer
|
serializer_class = serializers.RackGroupSerializer
|
||||||
filterset_class = filters.RackGroupFilter
|
filterset_class = filters.RackGroupFilter
|
||||||
|
|
||||||
@ -133,7 +137,9 @@ class RackGroupViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackRoleViewSet(ModelViewSet):
|
class RackRoleViewSet(ModelViewSet):
|
||||||
queryset = RackRole.objects.all()
|
queryset = RackRole.objects.annotate(
|
||||||
|
rack_count=Count('racks')
|
||||||
|
)
|
||||||
serializer_class = serializers.RackRoleSerializer
|
serializer_class = serializers.RackRoleSerializer
|
||||||
filterset_class = filters.RackRoleFilter
|
filterset_class = filters.RackRoleFilter
|
||||||
|
|
||||||
@ -143,7 +149,13 @@ class RackRoleViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackViewSet(CustomFieldModelViewSet):
|
class RackViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Rack.objects.select_related('site', 'group__site', 'tenant').prefetch_related('tags')
|
queryset = Rack.objects.select_related(
|
||||||
|
'site', 'group__site', 'tenant'
|
||||||
|
).prefetch_related(
|
||||||
|
'tags'
|
||||||
|
).annotate(
|
||||||
|
device_count=Count('devices')
|
||||||
|
)
|
||||||
serializer_class = serializers.RackSerializer
|
serializer_class = serializers.RackSerializer
|
||||||
filterset_class = filters.RackFilter
|
filterset_class = filters.RackFilter
|
||||||
|
|
||||||
@ -192,7 +204,9 @@ class RackReservationViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ManufacturerViewSet(ModelViewSet):
|
class ManufacturerViewSet(ModelViewSet):
|
||||||
queryset = Manufacturer.objects.all()
|
queryset = Manufacturer.objects.annotate(
|
||||||
|
devicetype_count=Count('device_types')
|
||||||
|
)
|
||||||
serializer_class = serializers.ManufacturerSerializer
|
serializer_class = serializers.ManufacturerSerializer
|
||||||
filterset_class = filters.ManufacturerFilter
|
filterset_class = filters.ManufacturerFilter
|
||||||
|
|
||||||
@ -202,7 +216,9 @@ class ManufacturerViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
||||||
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('tags')
|
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('tags').annotate(
|
||||||
|
device_count=Count('instances')
|
||||||
|
)
|
||||||
serializer_class = serializers.DeviceTypeSerializer
|
serializer_class = serializers.DeviceTypeSerializer
|
||||||
filterset_class = filters.DeviceTypeFilter
|
filterset_class = filters.DeviceTypeFilter
|
||||||
|
|
||||||
@ -264,7 +280,10 @@ class DeviceBayTemplateViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class DeviceRoleViewSet(ModelViewSet):
|
class DeviceRoleViewSet(ModelViewSet):
|
||||||
queryset = DeviceRole.objects.all()
|
queryset = DeviceRole.objects.annotate(
|
||||||
|
device_count=Count('devices', distinct=True),
|
||||||
|
virtualmachine_count=Count('virtual_machines', distinct=True)
|
||||||
|
)
|
||||||
serializer_class = serializers.DeviceRoleSerializer
|
serializer_class = serializers.DeviceRoleSerializer
|
||||||
filterset_class = filters.DeviceRoleFilter
|
filterset_class = filters.DeviceRoleFilter
|
||||||
|
|
||||||
@ -274,7 +293,10 @@ class DeviceRoleViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class PlatformViewSet(ModelViewSet):
|
class PlatformViewSet(ModelViewSet):
|
||||||
queryset = Platform.objects.all()
|
queryset = Platform.objects.annotate(
|
||||||
|
device_count=Count('devices', distinct=True),
|
||||||
|
virtualmachine_count=Count('virtual_machines', distinct=True)
|
||||||
|
)
|
||||||
serializer_class = serializers.PlatformSerializer
|
serializer_class = serializers.PlatformSerializer
|
||||||
filterset_class = filters.PlatformFilter
|
filterset_class = filters.PlatformFilter
|
||||||
|
|
||||||
@ -535,7 +557,9 @@ class CableViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VirtualChassisViewSet(ModelViewSet):
|
class VirtualChassisViewSet(ModelViewSet):
|
||||||
queryset = VirtualChassis.objects.prefetch_related('tags')
|
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
|
||||||
|
member_count=Count('members')
|
||||||
|
)
|
||||||
serializer_class = serializers.VirtualChassisSerializer
|
serializer_class = serializers.VirtualChassisSerializer
|
||||||
|
|
||||||
|
|
||||||
@ -544,7 +568,11 @@ class VirtualChassisViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class PowerPanelViewSet(ModelViewSet):
|
class PowerPanelViewSet(ModelViewSet):
|
||||||
queryset = PowerPanel.objects.select_related('site', 'rack_group')
|
queryset = PowerPanel.objects.select_related(
|
||||||
|
'site', 'rack_group'
|
||||||
|
).annotate(
|
||||||
|
powerfeed_count=Count('powerfeeds')
|
||||||
|
)
|
||||||
serializer_class = serializers.PowerPanelSerializer
|
serializer_class = serializers.PowerPanelSerializer
|
||||||
filterset_class = filters.PowerPanelFilter
|
filterset_class = filters.PowerPanelFilter
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class RegionTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'site_count', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_region(self):
|
def test_create_region(self):
|
||||||
@ -285,7 +285,7 @@ class RackGroupTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'rack_count', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_rackgroup(self):
|
def test_create_rackgroup(self):
|
||||||
@ -393,7 +393,7 @@ class RackRoleTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'rack_count', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_rackrole(self):
|
def test_create_rackrole(self):
|
||||||
@ -520,7 +520,7 @@ class RackTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['display_name', 'id', 'name', 'url']
|
['device_count', 'display_name', 'id', 'name', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_rack(self):
|
def test_create_rack(self):
|
||||||
@ -746,7 +746,7 @@ class ManufacturerTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['devicetype_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_manufacturer(self):
|
def test_create_manufacturer(self):
|
||||||
@ -855,7 +855,7 @@ class DeviceTypeTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['display_name', 'id', 'manufacturer', 'model', 'slug', 'url']
|
['device_count', 'display_name', 'id', 'manufacturer', 'model', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_devicetype(self):
|
def test_create_devicetype(self):
|
||||||
@ -1569,7 +1569,7 @@ class DeviceRoleTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['device_count', 'id', 'name', 'slug', 'url', 'virtualmachine_count']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_devicerole(self):
|
def test_create_devicerole(self):
|
||||||
@ -1677,7 +1677,7 @@ class PlatformTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['device_count', 'id', 'name', 'slug', 'url', 'virtualmachine_count']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_platform(self):
|
def test_create_platform(self):
|
||||||
@ -3457,7 +3457,7 @@ class VirtualChassisTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'master', 'url']
|
['id', 'master', 'member_count', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_virtualchassis(self):
|
def test_create_virtualchassis(self):
|
||||||
@ -3575,7 +3575,7 @@ class PowerPanelTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'url']
|
['id', 'name', 'powerfeed_count', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_powerpanel(self):
|
def test_create_powerpanel(self):
|
||||||
|
@ -21,10 +21,11 @@ __all__ = [
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VRF
|
model = VRF
|
||||||
fields = ['id', 'url', 'name', 'rd']
|
fields = ['id', 'url', 'name', 'rd', 'prefix_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -33,10 +34,11 @@ class NestedVRFSerializer(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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RIR
|
model = RIR
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'aggregate_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedAggregateSerializer(WritableNestedSerializer):
|
class NestedAggregateSerializer(WritableNestedSerializer):
|
||||||
@ -53,18 +55,21 @@ class NestedAggregateSerializer(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)
|
||||||
|
vlan_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Role
|
model = Role
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'prefix_count', 'vlan_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLANGroup
|
model = VLANGroup
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'vlan_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedVLANSerializer(WritableNestedSerializer):
|
class NestedVLANSerializer(WritableNestedSerializer):
|
||||||
|
@ -25,12 +25,13 @@ from .nested_serializers import *
|
|||||||
class VRFSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class VRFSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
prefix_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VRF
|
model = VRF
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name', 'custom_fields',
|
'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name', 'custom_fields',
|
||||||
'created', 'last_updated',
|
'created', 'last_updated', 'prefix_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -39,10 +40,11 @@ class VRFSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RIRSerializer(ValidatedModelSerializer):
|
class RIRSerializer(ValidatedModelSerializer):
|
||||||
|
aggregate_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RIR
|
model = RIR
|
||||||
fields = ['id', 'name', 'slug', 'is_private']
|
fields = ['id', 'name', 'slug', 'is_private', 'aggregate_count']
|
||||||
|
|
||||||
|
|
||||||
class AggregateSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class AggregateSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
@ -63,18 +65,21 @@ class AggregateSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RoleSerializer(ValidatedModelSerializer):
|
class RoleSerializer(ValidatedModelSerializer):
|
||||||
|
prefix_count = serializers.IntegerField(read_only=True)
|
||||||
|
vlan_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Role
|
model = Role
|
||||||
fields = ['id', 'name', 'slug', 'weight']
|
fields = ['id', 'name', 'slug', 'weight', 'prefix_count', 'vlan_count']
|
||||||
|
|
||||||
|
|
||||||
class VLANGroupSerializer(ValidatedModelSerializer):
|
class VLANGroupSerializer(ValidatedModelSerializer):
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = NestedSiteSerializer(required=False, allow_null=True)
|
||||||
|
vlan_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLANGroup
|
model = VLANGroup
|
||||||
fields = ['id', 'name', 'slug', 'site']
|
fields = ['id', 'name', 'slug', 'site', 'vlan_count']
|
||||||
validators = []
|
validators = []
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import Count, OuterRef, Subquery
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
@ -31,7 +32,9 @@ class IPAMFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VRFViewSet(CustomFieldModelViewSet):
|
class VRFViewSet(CustomFieldModelViewSet):
|
||||||
queryset = VRF.objects.select_related('tenant').prefetch_related('tags')
|
queryset = VRF.objects.select_related('tenant').prefetch_related('tags').annotate(
|
||||||
|
prefix_count=Count('prefixes')
|
||||||
|
)
|
||||||
serializer_class = serializers.VRFSerializer
|
serializer_class = serializers.VRFSerializer
|
||||||
filterset_class = filters.VRFFilter
|
filterset_class = filters.VRFFilter
|
||||||
|
|
||||||
@ -41,7 +44,9 @@ class VRFViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RIRViewSet(ModelViewSet):
|
class RIRViewSet(ModelViewSet):
|
||||||
queryset = RIR.objects.all()
|
queryset = RIR.objects.annotate(
|
||||||
|
aggregate_count=Count('aggregates')
|
||||||
|
)
|
||||||
serializer_class = serializers.RIRSerializer
|
serializer_class = serializers.RIRSerializer
|
||||||
filterset_class = filters.RIRFilter
|
filterset_class = filters.RIRFilter
|
||||||
|
|
||||||
@ -61,7 +66,10 @@ class AggregateViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RoleViewSet(ModelViewSet):
|
class RoleViewSet(ModelViewSet):
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.annotate(
|
||||||
|
prefix_count=Count('prefixes', distinct=True),
|
||||||
|
vlan_count=Count('vlans', distinct=True)
|
||||||
|
)
|
||||||
serializer_class = serializers.RoleSerializer
|
serializer_class = serializers.RoleSerializer
|
||||||
filterset_class = filters.RoleFilter
|
filterset_class = filters.RoleFilter
|
||||||
|
|
||||||
@ -71,7 +79,11 @@ class RoleViewSet(ModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class PrefixViewSet(CustomFieldModelViewSet):
|
class PrefixViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role').prefetch_related('tags')
|
queryset = Prefix.objects.select_related(
|
||||||
|
'site', 'vrf__tenant', 'tenant', 'vlan', 'role'
|
||||||
|
).prefetch_related(
|
||||||
|
'tags'
|
||||||
|
)
|
||||||
serializer_class = serializers.PrefixSerializer
|
serializer_class = serializers.PrefixSerializer
|
||||||
filterset_class = filters.PrefixFilter
|
filterset_class = filters.PrefixFilter
|
||||||
|
|
||||||
@ -263,7 +275,9 @@ class IPAddressViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VLANGroupViewSet(ModelViewSet):
|
class VLANGroupViewSet(ModelViewSet):
|
||||||
queryset = VLANGroup.objects.select_related('site')
|
queryset = VLANGroup.objects.select_related('site').annotate(
|
||||||
|
vlan_count=Count('vlans')
|
||||||
|
)
|
||||||
serializer_class = serializers.VLANGroupSerializer
|
serializer_class = serializers.VLANGroupSerializer
|
||||||
filterset_class = filters.VLANGroupFilter
|
filterset_class = filters.VLANGroupFilter
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class VRFTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'rd', 'url']
|
['id', 'name', 'prefix_count', 'rd', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_vrf(self):
|
def test_create_vrf(self):
|
||||||
@ -147,7 +147,7 @@ class RIRTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['aggregate_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_rir(self):
|
def test_create_rir(self):
|
||||||
@ -351,7 +351,7 @@ class RoleTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'prefix_count', 'slug', 'url', 'vlan_count']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_role(self):
|
def test_create_role(self):
|
||||||
@ -790,7 +790,7 @@ class VLANGroupTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'slug', 'url', 'vlan_count']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_vlangroup(self):
|
def test_create_vlangroup(self):
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import QuerySet
|
||||||
from rest_framework import authentication, exceptions
|
from rest_framework import authentication, exceptions
|
||||||
from rest_framework.pagination import LimitOffsetPagination
|
from rest_framework.pagination import LimitOffsetPagination
|
||||||
from rest_framework.permissions import DjangoModelPermissions, SAFE_METHODS
|
from rest_framework.permissions import DjangoModelPermissions, SAFE_METHODS
|
||||||
@ -96,13 +97,8 @@ class OptionalLimitOffsetPagination(LimitOffsetPagination):
|
|||||||
|
|
||||||
def paginate_queryset(self, queryset, request, view=None):
|
def paginate_queryset(self, queryset, request, view=None):
|
||||||
|
|
||||||
if hasattr(queryset, 'all'):
|
if type(queryset) is QuerySet:
|
||||||
# TODO: This breaks filtering by annotated values
|
self.count = queryset.count()
|
||||||
# Make a clone of the queryset with any annotations stripped (performance hack)
|
|
||||||
qs = queryset.all()
|
|
||||||
qs.query.annotations.clear()
|
|
||||||
self.count = qs.count()
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# We're dealing with an iterable, not a QuerySet
|
# We're dealing with an iterable, not a QuerySet
|
||||||
self.count = len(queryset)
|
self.count = len(queryset)
|
||||||
|
@ -10,7 +10,8 @@ __all__ = [
|
|||||||
|
|
||||||
class NestedSecretRoleSerializer(WritableNestedSerializer):
|
class NestedSecretRoleSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='secrets-api:secretrole-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='secrets-api:secretrole-detail')
|
||||||
|
secret_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SecretRole
|
model = SecretRole
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'secret_count']
|
||||||
|
@ -14,10 +14,11 @@ from .nested_serializers import *
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SecretRoleSerializer(ValidatedModelSerializer):
|
class SecretRoleSerializer(ValidatedModelSerializer):
|
||||||
|
secret_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SecretRole
|
model = SecretRole
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'secret_count']
|
||||||
|
|
||||||
|
|
||||||
class SecretSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class SecretSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import base64
|
import base64
|
||||||
|
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
|
from django.db.models import Count
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
@ -32,7 +33,9 @@ class SecretsFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SecretRoleViewSet(ModelViewSet):
|
class SecretRoleViewSet(ModelViewSet):
|
||||||
queryset = SecretRole.objects.all()
|
queryset = SecretRole.objects.annotate(
|
||||||
|
secret_count=Count('secrets')
|
||||||
|
)
|
||||||
serializer_class = serializers.SecretRoleSerializer
|
serializer_class = serializers.SecretRoleSerializer
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
filterset_class = filters.SecretRoleFilter
|
filterset_class = filters.SecretRoleFilter
|
||||||
|
@ -78,7 +78,7 @@ class SecretRoleTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'secret_count', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_secretrole(self):
|
def test_create_secretrole(self):
|
||||||
|
@ -15,10 +15,11 @@ __all__ = [
|
|||||||
|
|
||||||
class NestedTenantGroupSerializer(WritableNestedSerializer):
|
class NestedTenantGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
|
||||||
|
tenant_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'tenant_count']
|
||||||
|
|
||||||
|
|
||||||
class NestedTenantSerializer(WritableNestedSerializer):
|
class NestedTenantSerializer(WritableNestedSerializer):
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
|
from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
|
||||||
|
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
@ -11,10 +12,11 @@ from .nested_serializers import *
|
|||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupSerializer(ValidatedModelSerializer):
|
class TenantGroupSerializer(ValidatedModelSerializer):
|
||||||
|
tenant_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'tenant_count']
|
||||||
|
|
||||||
|
|
||||||
class TenantSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class TenantSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
from tenancy import filters
|
from tenancy import filters
|
||||||
from tenancy.models import Tenant, TenantGroup
|
from tenancy.models import Tenant, TenantGroup
|
||||||
@ -18,7 +20,9 @@ class TenancyFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupViewSet(ModelViewSet):
|
class TenantGroupViewSet(ModelViewSet):
|
||||||
queryset = TenantGroup.objects.all()
|
queryset = TenantGroup.objects.annotate(
|
||||||
|
tenant_count=Count('tenants')
|
||||||
|
)
|
||||||
serializer_class = serializers.TenantGroupSerializer
|
serializer_class = serializers.TenantGroupSerializer
|
||||||
filterset_class = filters.TenantGroupFilter
|
filterset_class = filters.TenantGroupFilter
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class TenantGroupTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['id', 'name', 'slug', 'tenant_count', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_tenantgroup(self):
|
def test_create_tenantgroup(self):
|
||||||
|
@ -19,26 +19,29 @@ __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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterType
|
model = ClusterType
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'cluster_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterGroup
|
model = ClusterGroup
|
||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug', 'cluster_count']
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = ['id', 'url', 'name']
|
fields = ['id', 'url', 'name', 'virtualmachine_count']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -20,17 +20,19 @@ from .nested_serializers import *
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ClusterTypeSerializer(ValidatedModelSerializer):
|
class ClusterTypeSerializer(ValidatedModelSerializer):
|
||||||
|
cluster_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterType
|
model = ClusterType
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'cluster_count']
|
||||||
|
|
||||||
|
|
||||||
class ClusterGroupSerializer(ValidatedModelSerializer):
|
class ClusterGroupSerializer(ValidatedModelSerializer):
|
||||||
|
cluster_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterGroup
|
model = ClusterGroup
|
||||||
fields = ['id', 'name', 'slug']
|
fields = ['id', 'name', 'slug', 'cluster_count']
|
||||||
|
|
||||||
|
|
||||||
class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
||||||
@ -38,11 +40,13 @@ class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
|
|||||||
group = NestedClusterGroupSerializer(required=False, allow_null=True)
|
group = NestedClusterGroupSerializer(required=False, allow_null=True)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = NestedSiteSerializer(required=False, allow_null=True)
|
||||||
tags = TagListSerializerField(required=False)
|
tags = TagListSerializerField(required=False)
|
||||||
|
virtualmachine_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'type', 'group', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
'id', 'name', 'type', 'group', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
|
'virtualmachine_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
from extras.api.views import CustomFieldModelViewSet
|
from extras.api.views import CustomFieldModelViewSet
|
||||||
from utilities.api import FieldChoicesViewSet, ModelViewSet
|
from utilities.api import FieldChoicesViewSet, ModelViewSet
|
||||||
@ -21,19 +23,25 @@ class VirtualizationFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ClusterTypeViewSet(ModelViewSet):
|
class ClusterTypeViewSet(ModelViewSet):
|
||||||
queryset = ClusterType.objects.all()
|
queryset = ClusterType.objects.annotate(
|
||||||
|
cluster_count=Count('clusters')
|
||||||
|
)
|
||||||
serializer_class = serializers.ClusterTypeSerializer
|
serializer_class = serializers.ClusterTypeSerializer
|
||||||
filterset_class = filters.ClusterTypeFilter
|
filterset_class = filters.ClusterTypeFilter
|
||||||
|
|
||||||
|
|
||||||
class ClusterGroupViewSet(ModelViewSet):
|
class ClusterGroupViewSet(ModelViewSet):
|
||||||
queryset = ClusterGroup.objects.all()
|
queryset = ClusterGroup.objects.annotate(
|
||||||
|
cluster_count=Count('clusters')
|
||||||
|
)
|
||||||
serializer_class = serializers.ClusterGroupSerializer
|
serializer_class = serializers.ClusterGroupSerializer
|
||||||
filterset_class = filters.ClusterGroupFilter
|
filterset_class = filters.ClusterGroupFilter
|
||||||
|
|
||||||
|
|
||||||
class ClusterViewSet(CustomFieldModelViewSet):
|
class ClusterViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Cluster.objects.select_related('type', 'group').prefetch_related('tags')
|
queryset = Cluster.objects.select_related('type', 'group').prefetch_related('tags').annotate(
|
||||||
|
virtualmachine_count=Count('virtual_machines')
|
||||||
|
)
|
||||||
serializer_class = serializers.ClusterSerializer
|
serializer_class = serializers.ClusterSerializer
|
||||||
filterset_class = filters.ClusterFilter
|
filterset_class = filters.ClusterFilter
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class ClusterTypeTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['cluster_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_clustertype(self):
|
def test_create_clustertype(self):
|
||||||
@ -141,7 +141,7 @@ class ClusterGroupTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'slug', 'url']
|
['cluster_count', 'id', 'name', 'slug', 'url']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_clustergroup(self):
|
def test_create_clustergroup(self):
|
||||||
@ -245,7 +245,7 @@ class ClusterTest(APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(response.data['results'][0]),
|
sorted(response.data['results'][0]),
|
||||||
['id', 'name', 'url']
|
['id', 'name', 'url', 'virtualmachine_count']
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_create_cluster(self):
|
def test_create_cluster(self):
|
||||||
|
Reference in New Issue
Block a user