Closes #15131: Dynamic queryset annotations for REST API endpoints (#15152)

* Introduce RelatedObjectCountField

* Introduce get_annotations_for_serializer() and enable dynamic annotations

* Add RelatedObjectCountFields to serializers; remove static annotations from querysets

* Remove annotations cleanup logic from BriefModeMixin

* Annotate type for RelatedObjectCountField

* Remove redundant field on TagSerializer

* Add missing reverse relationship for power feeds to rack

* Refactor RelatedObjectCountField to take a single relationship name
This commit is contained in:
Jeremy Stretch
2024-02-15 14:49:27 -05:00
committed by GitHub
parent b3f25a400b
commit 7abb2b2ab5
27 changed files with 204 additions and 221 deletions

View File

@@ -13,7 +13,6 @@ from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH
from dcim.models import *
from dcim.svg import CableTraceSVG
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
from ipam.models import Prefix, VLAN
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
from netbox.api.metadata import ContentTypeMetadata
from netbox.api.pagination import StripCountAnnotationsPaginator
@@ -23,7 +22,6 @@ from netbox.constants import NESTED_SERIALIZER_PREFIX
from utilities.api import get_serializer_for_model
from utilities.query_functions import CollateAsChar
from utilities.utils import count_related
from virtualization.models import VirtualMachine
from . import serializers
from .exceptions import MissingFilterException
@@ -129,14 +127,7 @@ class SiteGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
#
class SiteViewSet(NetBoxModelViewSet):
queryset = Site.objects.annotate(
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')
)
queryset = Site.objects.all()
serializer_class = serializers.SiteSerializer
filterset_class = filtersets.SiteFilterSet
@@ -168,9 +159,7 @@ class LocationViewSet(MPTTLockedMixin, NetBoxModelViewSet):
#
class RackRoleViewSet(NetBoxModelViewSet):
queryset = RackRole.objects.annotate(
rack_count=count_related(Rack, 'role')
)
queryset = RackRole.objects.all()
serializer_class = serializers.RackRoleSerializer
filterset_class = filtersets.RackRoleFilterSet
@@ -180,10 +169,7 @@ class RackRoleViewSet(NetBoxModelViewSet):
#
class RackViewSet(NetBoxModelViewSet):
queryset = Rack.objects.annotate(
device_count=count_related(Device, 'rack'),
powerfeed_count=count_related(PowerFeed, 'rack')
)
queryset = Rack.objects.all()
serializer_class = serializers.RackSerializer
filterset_class = filtersets.RackFilterSet
@@ -255,11 +241,7 @@ class RackReservationViewSet(NetBoxModelViewSet):
#
class ManufacturerViewSet(NetBoxModelViewSet):
queryset = Manufacturer.objects.annotate(
devicetype_count=count_related(DeviceType, 'manufacturer'),
inventoryitem_count=count_related(InventoryItem, 'manufacturer'),
platform_count=count_related(Platform, 'manufacturer')
)
queryset = Manufacturer.objects.all()
serializer_class = serializers.ManufacturerSerializer
filterset_class = filtersets.ManufacturerFilterSet
@@ -269,9 +251,7 @@ class ManufacturerViewSet(NetBoxModelViewSet):
#
class DeviceTypeViewSet(NetBoxModelViewSet):
queryset = DeviceType.objects.annotate(
device_count=count_related(Device, 'device_type')
)
queryset = DeviceType.objects.all()
serializer_class = serializers.DeviceTypeSerializer
filterset_class = filtersets.DeviceTypeFilterSet
@@ -351,10 +331,7 @@ class InventoryItemTemplateViewSet(MPTTLockedMixin, NetBoxModelViewSet):
#
class DeviceRoleViewSet(NetBoxModelViewSet):
queryset = DeviceRole.objects.annotate(
device_count=count_related(Device, 'role'),
virtualmachine_count=count_related(VirtualMachine, 'role')
)
queryset = DeviceRole.objects.all()
serializer_class = serializers.DeviceRoleSerializer
filterset_class = filtersets.DeviceRoleFilterSet
@@ -364,10 +341,7 @@ class DeviceRoleViewSet(NetBoxModelViewSet):
#
class PlatformViewSet(NetBoxModelViewSet):
queryset = Platform.objects.annotate(
device_count=count_related(Device, 'platform'),
virtualmachine_count=count_related(VirtualMachine, 'platform')
)
queryset = Platform.objects.all()
serializer_class = serializers.PlatformSerializer
filterset_class = filtersets.PlatformFilterSet
@@ -410,9 +384,7 @@ class DeviceViewSet(
class VirtualDeviceContextViewSet(NetBoxModelViewSet):
queryset = VirtualDeviceContext.objects.annotate(
interface_count=count_related(Interface, 'vdcs'),
)
queryset = VirtualDeviceContext.objects.all()
serializer_class = serializers.VirtualDeviceContextSerializer
filterset_class = filtersets.VirtualDeviceContextFilterSet
@@ -513,9 +485,7 @@ class InventoryItemViewSet(MPTTLockedMixin, NetBoxModelViewSet):
#
class InventoryItemRoleViewSet(NetBoxModelViewSet):
queryset = InventoryItemRole.objects.annotate(
inventoryitem_count=count_related(InventoryItem, 'role')
)
queryset = InventoryItemRole.objects.all()
serializer_class = serializers.InventoryItemRoleSerializer
filterset_class = filtersets.InventoryItemRoleFilterSet
@@ -552,9 +522,7 @@ class VirtualChassisViewSet(NetBoxModelViewSet):
#
class PowerPanelViewSet(NetBoxModelViewSet):
queryset = PowerPanel.objects.annotate(
powerfeed_count=count_related(PowerFeed, 'power_panel')
)
queryset = PowerPanel.objects.all()
serializer_class = serializers.PowerPanelSerializer
filterset_class = filtersets.PowerPanelFilterSet