Просмотр исходного кода

Add dynamic nesting support to SerializedPKRelatedField

Jeremy Stretch 2 лет назад
Родитель
Сommit
ca56c8b9ef

+ 3 - 2
netbox/circuits/api/serializers_/providers.py

@@ -1,7 +1,7 @@
 from rest_framework import serializers
 from rest_framework import serializers
 
 
 from circuits.models import Provider, ProviderAccount, ProviderNetwork
 from circuits.models import Provider, ProviderAccount, ProviderNetwork
-from ipam.api.nested_serializers import NestedASNSerializer
+from ipam.api.serializers_.asns import ASNSerializer
 from ipam.models import ASN
 from ipam.models import ASN
 from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
@@ -24,7 +24,8 @@ class ProviderSerializer(NetBoxModelSerializer):
     )
     )
     asns = SerializedPKRelatedField(
     asns = SerializedPKRelatedField(
         queryset=ASN.objects.all(),
         queryset=ASN.objects.all(),
-        serializer=NestedASNSerializer,
+        serializer=ASNSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 9 - 6
netbox/dcim/api/serializers_/device_components.py

@@ -10,21 +10,21 @@ from dcim.models import (
 )
 )
 from ipam.api.serializers_.vlans import VLANSerializer
 from ipam.api.serializers_.vlans import VLANSerializer
 from ipam.api.serializers_.vrfs import VRFSerializer
 from ipam.api.serializers_.vrfs import VRFSerializer
-from ipam.api.nested_serializers import NestedVLANSerializer
 from ipam.models import VLAN
 from ipam.models import VLAN
 from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
 from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
 from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
 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 vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
 from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
-from wireless.api.nested_serializers import NestedWirelessLANSerializer, NestedWirelessLinkSerializer
+from wireless.api.nested_serializers import NestedWirelessLinkSerializer
 from wireless.choices import *
 from wireless.choices import *
 from wireless.models import WirelessLAN
 from wireless.models import WirelessLAN
 from .base import ConnectedEndpointsSerializer
 from .base import ConnectedEndpointsSerializer
 from .cables import CabledObjectSerializer
 from .cables import CabledObjectSerializer
-from .devices import DeviceSerializer, ModuleSerializer
+from .devices import DeviceSerializer, ModuleSerializer, VirtualDeviceContextSerializer
 from .manufacturers import ManufacturerSerializer
 from .manufacturers import ManufacturerSerializer
 from .roles import InventoryItemRoleSerializer
 from .roles import InventoryItemRoleSerializer
+from wireless.api.serializers_.wirelesslans import WirelessLANSerializer
 from ..nested_serializers import *
 from ..nested_serializers import *
 
 
 __all__ = (
 __all__ = (
@@ -173,7 +173,8 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     vdcs = SerializedPKRelatedField(
     vdcs = SerializedPKRelatedField(
         queryset=VirtualDeviceContext.objects.all(),
         queryset=VirtualDeviceContext.objects.all(),
-        serializer=NestedVirtualDeviceContextSerializer,
+        serializer=VirtualDeviceContextSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -196,7 +197,8 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     untagged_vlan = VLANSerializer(nested=True, required=False, allow_null=True)
     untagged_vlan = VLANSerializer(nested=True, required=False, allow_null=True)
     tagged_vlans = SerializedPKRelatedField(
     tagged_vlans = SerializedPKRelatedField(
         queryset=VLAN.objects.all(),
         queryset=VLAN.objects.all(),
-        serializer=NestedVLANSerializer,
+        serializer=VLANSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -205,7 +207,8 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     wireless_link = NestedWirelessLinkSerializer(read_only=True, allow_null=True)
     wireless_link = NestedWirelessLinkSerializer(read_only=True, allow_null=True)
     wireless_lans = SerializedPKRelatedField(
     wireless_lans = SerializedPKRelatedField(
         queryset=WirelessLAN.objects.all(),
         queryset=WirelessLAN.objects.all(),
-        serializer=NestedWirelessLANSerializer,
+        serializer=WirelessLANSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 1 - 1
netbox/dcim/api/serializers_/devices.py

@@ -6,7 +6,7 @@ from rest_framework import serializers
 
 
 from dcim.choices import *
 from dcim.choices import *
 from dcim.models import Device, DeviceBay, Module, VirtualDeviceContext
 from dcim.models import Device, DeviceBay, Module, VirtualDeviceContext
-from extras.api.serializers_.provisioning import ConfigTemplateSerializer
+from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
 from ipam.api.serializers_.ip import IPAddressSerializer
 from ipam.api.serializers_.ip import IPAddressSerializer
 from netbox.api.fields import ChoiceField, RelatedObjectCountField
 from netbox.api.fields import ChoiceField, RelatedObjectCountField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer

+ 1 - 1
netbox/dcim/api/serializers_/platforms.py

@@ -1,7 +1,7 @@
 from rest_framework import serializers
 from rest_framework import serializers
 
 
 from dcim.models import Platform
 from dcim.models import Platform
-from extras.api.serializers_.provisioning import ConfigTemplateSerializer
+from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
 from .manufacturers import ManufacturerSerializer
 from .manufacturers import ManufacturerSerializer

+ 1 - 1
netbox/dcim/api/serializers_/roles.py

@@ -1,7 +1,7 @@
 from rest_framework import serializers
 from rest_framework import serializers
 
 
 from dcim.models import DeviceRole, InventoryItemRole
 from dcim.models import DeviceRole, InventoryItemRole
-from extras.api.serializers_.provisioning import ConfigTemplateSerializer
+from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
 
 

+ 3 - 2
netbox/dcim/api/serializers_/sites.py

@@ -3,7 +3,7 @@ from timezone_field.rest_framework import TimeZoneSerializerField
 
 
 from dcim.choices import *
 from dcim.choices import *
 from dcim.models import Location, Region, Site, SiteGroup
 from dcim.models import Location, Region, Site, SiteGroup
-from ipam.api.nested_serializers import NestedASNSerializer
+from ipam.api.serializers_.asns import ASNSerializer
 from ipam.models import ASN
 from ipam.models import ASN
 from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
 from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
@@ -55,7 +55,8 @@ class SiteSerializer(NetBoxModelSerializer):
     time_zone = TimeZoneSerializerField(required=False, allow_null=True)
     time_zone = TimeZoneSerializerField(required=False, allow_null=True)
     asns = SerializedPKRelatedField(
     asns = SerializedPKRelatedField(
         queryset=ASN.objects.all(),
         queryset=ASN.objects.all(),
-        serializer=NestedASNSerializer,
+        serializer=ASNSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 2 - 1
netbox/extras/api/serializers.py

@@ -8,7 +8,8 @@ from .serializers_.dashboard import *
 from .serializers_.events import *
 from .serializers_.events import *
 from .serializers_.exporttemplates import *
 from .serializers_.exporttemplates import *
 from .serializers_.journaling import *
 from .serializers_.journaling import *
-from .serializers_.provisioning import *
+from .serializers_.configcontexts import *
+from .serializers_.configtemplates import *
 from .serializers_.savedfilters import *
 from .serializers_.savedfilters import *
 from .serializers_.scripts import *
 from .serializers_.scripts import *
 from .serializers_.tags import *
 from .serializers_.tags import *

+ 31 - 47
netbox/extras/api/serializers_/provisioning.py → netbox/extras/api/serializers_/configcontexts.py

@@ -1,25 +1,21 @@
 from rest_framework import serializers
 from rest_framework import serializers
 
 
 from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer
 from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer
-from dcim.api.nested_serializers import (
-    NestedDeviceRoleSerializer, NestedDeviceTypeSerializer, NestedLocationSerializer, NestedPlatformSerializer,
-    NestedRegionSerializer, NestedSiteSerializer, NestedSiteGroupSerializer,
-)
+from dcim.api.serializers_.devicetypes import DeviceTypeSerializer
+from dcim.api.serializers_.platforms import PlatformSerializer
+from dcim.api.serializers_.roles import DeviceRoleSerializer
+from dcim.api.serializers_.sites import LocationSerializer, RegionSerializer, SiteSerializer, SiteGroupSerializer
 from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
 from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
-from extras.models import ConfigContext, ConfigTemplate, Tag
+from extras.models import ConfigContext, Tag
 from netbox.api.fields import SerializedPKRelatedField
 from netbox.api.fields import SerializedPKRelatedField
 from netbox.api.serializers import ValidatedModelSerializer
 from netbox.api.serializers import ValidatedModelSerializer
-from netbox.api.serializers.features import TaggableModelSerializer
-from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
+from tenancy.api.serializers_.tenants import TenantSerializer, TenantGroupSerializer
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
-from virtualization.api.nested_serializers import (
-    NestedClusterGroupSerializer, NestedClusterSerializer, NestedClusterTypeSerializer,
-)
+from virtualization.api.serializers_.clusters import ClusterSerializer, ClusterGroupSerializer, ClusterTypeSerializer
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 
 
 __all__ = (
 __all__ = (
     'ConfigContextSerializer',
     'ConfigContextSerializer',
-    'ConfigTemplateSerializer',
 )
 )
 
 
 
 
@@ -27,73 +23,85 @@ class ConfigContextSerializer(ValidatedModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
     url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
     regions = SerializedPKRelatedField(
     regions = SerializedPKRelatedField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        serializer=NestedRegionSerializer,
+        serializer=RegionSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     site_groups = SerializedPKRelatedField(
     site_groups = SerializedPKRelatedField(
         queryset=SiteGroup.objects.all(),
         queryset=SiteGroup.objects.all(),
-        serializer=NestedSiteGroupSerializer,
+        serializer=SiteGroupSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     sites = SerializedPKRelatedField(
     sites = SerializedPKRelatedField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        serializer=NestedSiteSerializer,
+        serializer=SiteSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     locations = SerializedPKRelatedField(
     locations = SerializedPKRelatedField(
         queryset=Location.objects.all(),
         queryset=Location.objects.all(),
-        serializer=NestedLocationSerializer,
+        serializer=LocationSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     device_types = SerializedPKRelatedField(
     device_types = SerializedPKRelatedField(
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),
-        serializer=NestedDeviceTypeSerializer,
+        serializer=DeviceTypeSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     roles = SerializedPKRelatedField(
     roles = SerializedPKRelatedField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
-        serializer=NestedDeviceRoleSerializer,
+        serializer=DeviceRoleSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     platforms = SerializedPKRelatedField(
     platforms = SerializedPKRelatedField(
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
-        serializer=NestedPlatformSerializer,
+        serializer=PlatformSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     cluster_types = SerializedPKRelatedField(
     cluster_types = SerializedPKRelatedField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
-        serializer=NestedClusterTypeSerializer,
+        serializer=ClusterTypeSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     cluster_groups = SerializedPKRelatedField(
     cluster_groups = SerializedPKRelatedField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
-        serializer=NestedClusterGroupSerializer,
+        serializer=ClusterGroupSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     clusters = SerializedPKRelatedField(
     clusters = SerializedPKRelatedField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
-        serializer=NestedClusterSerializer,
+        serializer=ClusterSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     tenant_groups = SerializedPKRelatedField(
     tenant_groups = SerializedPKRelatedField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
-        serializer=NestedTenantGroupSerializer,
+        serializer=TenantGroupSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     tenants = SerializedPKRelatedField(
     tenants = SerializedPKRelatedField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
-        serializer=NestedTenantSerializer,
+        serializer=TenantSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -121,27 +129,3 @@ class ConfigContextSerializer(ValidatedModelSerializer):
             'created', 'last_updated',
             'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
-
-
-#
-# Config templates
-#
-
-class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
-    data_source = DataSourceSerializer(
-        nested=True,
-        required=False
-    )
-    data_file = DataFileSerializer(
-        nested=True,
-        required=False
-    )
-
-    class Meta:
-        model = ConfigTemplate
-        fields = [
-            'id', 'url', 'display', 'name', 'description', 'environment_params', 'template_code', 'data_source',
-            'data_path', 'data_file', 'data_synced', 'tags', 'created', 'last_updated',
-        ]
-        brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 30 - 0
netbox/extras/api/serializers_/configtemplates.py

@@ -0,0 +1,30 @@
+from rest_framework import serializers
+
+from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer
+from extras.models import ConfigTemplate
+from netbox.api.serializers import ValidatedModelSerializer
+from netbox.api.serializers.features import TaggableModelSerializer
+
+__all__ = (
+    'ConfigTemplateSerializer',
+)
+
+
+class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
+    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
+    data_source = DataSourceSerializer(
+        nested=True,
+        required=False
+    )
+    data_file = DataFileSerializer(
+        nested=True,
+        required=False
+    )
+
+    class Meta:
+        model = ConfigTemplate
+        fields = [
+            'id', 'url', 'display', 'name', 'description', 'environment_params', 'template_code', 'data_source',
+            'data_path', 'data_file', 'data_synced', 'tags', 'created', 'last_updated',
+        ]
+        brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 2 - 2
netbox/extras/api/serializers_/events.py

@@ -9,7 +9,7 @@ from netbox.api.fields import ChoiceField, ContentTypeField
 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 utilities.api import get_serializer_for_model
 from utilities.api import get_serializer_for_model
-from ..nested_serializers import *
+from .scripts import ScriptSerializer
 
 
 __all__ = (
 __all__ = (
     'EventRuleSerializer',
     'EventRuleSerializer',
@@ -49,7 +49,7 @@ class EventRuleSerializer(NetBoxModelSerializer):
         if instance.action_type == EventRuleActionChoices.SCRIPT:
         if instance.action_type == EventRuleActionChoices.SCRIPT:
             script = instance.action_object
             script = instance.action_object
             instance = script.python_class() if script.python_class else None
             instance = script.python_class() if script.python_class else None
-            return NestedScriptSerializer(instance, context=context).data
+            return ScriptSerializer(instance, nested=True, context=context).data
         else:
         else:
             serializer = get_serializer_for_model(
             serializer = get_serializer_for_model(
                 model=instance.action_object_type.model_class(),
                 model=instance.action_object_type.model_class(),

+ 2 - 2
netbox/ipam/api/serializers_/fhrpgroups.py

@@ -7,7 +7,7 @@ from netbox.api.fields import ContentTypeField
 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 utilities.api import get_serializer_for_model
 from utilities.api import get_serializer_for_model
-from ..nested_serializers import *
+from .ip import IPAddressSerializer
 
 
 __all__ = (
 __all__ = (
     'FHRPGroupAssignmentSerializer',
     'FHRPGroupAssignmentSerializer',
@@ -17,7 +17,7 @@ __all__ = (
 
 
 class FHRPGroupSerializer(NetBoxModelSerializer):
 class FHRPGroupSerializer(NetBoxModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroup-detail')
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroup-detail')
-    ip_addresses = NestedIPAddressSerializer(many=True, read_only=True)
+    ip_addresses = IPAddressSerializer(nested=True, many=True, read_only=True)
 
 
     class Meta:
     class Meta:
         model = FHRPGroup
         model = FHRPGroup

+ 3 - 2
netbox/ipam/api/serializers_/services.py

@@ -6,7 +6,7 @@ from ipam.models import IPAddress, Service, ServiceTemplate
 from netbox.api.fields import ChoiceField, SerializedPKRelatedField
 from netbox.api.fields import ChoiceField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
 from virtualization.api.serializers_.virtualmachines import VirtualMachineSerializer
 from virtualization.api.serializers_.virtualmachines import VirtualMachineSerializer
-from ..nested_serializers import *
+from .ip import IPAddressSerializer
 
 
 __all__ = (
 __all__ = (
     'ServiceSerializer',
     'ServiceSerializer',
@@ -34,7 +34,8 @@ class ServiceSerializer(NetBoxModelSerializer):
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
     ipaddresses = SerializedPKRelatedField(
     ipaddresses = SerializedPKRelatedField(
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
-        serializer=NestedIPAddressSerializer,
+        serializer=IPAddressSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 15 - 16
netbox/ipam/api/serializers_/vrfs.py

@@ -4,7 +4,6 @@ from ipam.models import RouteTarget, VRF
 from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
-from ..nested_serializers import *
 
 
 __all__ = (
 __all__ = (
     'RouteTargetSerializer',
     'RouteTargetSerializer',
@@ -12,18 +11,31 @@ __all__ = (
 )
 )
 
 
 
 
+class RouteTargetSerializer(NetBoxModelSerializer):
+    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
+    tenant = TenantSerializer(nested=True, required=False, allow_null=True)
+
+    class Meta:
+        model = RouteTarget
+        fields = [
+            'id', 'url', 'display', 'name', 'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created',
+            'last_updated',
+        ]
+        brief_fields = ('id', 'url', 'display', 'name', 'description')
+
+
 class VRFSerializer(NetBoxModelSerializer):
 class VRFSerializer(NetBoxModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
     url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     import_targets = SerializedPKRelatedField(
     import_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        serializer=NestedRouteTargetSerializer,
+        serializer=RouteTargetSerializer,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     export_targets = SerializedPKRelatedField(
     export_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        serializer=NestedRouteTargetSerializer,
+        serializer=RouteTargetSerializer,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -40,16 +52,3 @@ class VRFSerializer(NetBoxModelSerializer):
             'prefix_count',
             'prefix_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count')
         brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count')
-
-
-class RouteTargetSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
-    tenant = TenantSerializer(nested=True, required=False, allow_null=True)
-
-    class Meta:
-        model = RouteTarget
-        fields = [
-            'id', 'url', 'display', 'name', 'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created',
-            'last_updated',
-        ]
-        brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 4 - 2
netbox/netbox/api/fields.py

@@ -132,13 +132,15 @@ class SerializedPKRelatedField(PrimaryKeyRelatedField):
     Extends PrimaryKeyRelatedField to return a serialized object on read. This is useful for representing related
     Extends PrimaryKeyRelatedField to return a serialized object on read. This is useful for representing related
     objects in a ManyToManyField while still allowing a set of primary keys to be written.
     objects in a ManyToManyField while still allowing a set of primary keys to be written.
     """
     """
-    def __init__(self, serializer, **kwargs):
+    def __init__(self, serializer, nested=False, **kwargs):
         self.serializer = serializer
         self.serializer = serializer
+        self.nested = nested
         self.pk_field = kwargs.pop('pk_field', None)
         self.pk_field = kwargs.pop('pk_field', None)
+
         super().__init__(**kwargs)
         super().__init__(**kwargs)
 
 
     def to_representation(self, value):
     def to_representation(self, value):
-        return self.serializer(value, context={'request': self.context['request']}).data
+        return self.serializer(value, nested=self.nested, context={'request': self.context['request']}).data
 
 
 
 
 @extend_schema_field(OpenApiTypes.INT64)
 @extend_schema_field(OpenApiTypes.INT64)

+ 5 - 3
netbox/users/api/serializers_/permissions.py

@@ -6,7 +6,7 @@ from rest_framework import serializers
 from netbox.api.fields import ContentTypeField, SerializedPKRelatedField
 from netbox.api.fields import ContentTypeField, SerializedPKRelatedField
 from netbox.api.serializers import ValidatedModelSerializer
 from netbox.api.serializers import ValidatedModelSerializer
 from users.models import ObjectPermission
 from users.models import ObjectPermission
-from ..nested_serializers import *
+from .users import GroupSerializer, UserSerializer
 
 
 __all__ = (
 __all__ = (
     'ObjectPermissionSerializer',
     'ObjectPermissionSerializer',
@@ -21,13 +21,15 @@ class ObjectPermissionSerializer(ValidatedModelSerializer):
     )
     )
     groups = SerializedPKRelatedField(
     groups = SerializedPKRelatedField(
         queryset=Group.objects.all(),
         queryset=Group.objects.all(),
-        serializer=NestedGroupSerializer,
+        serializer=GroupSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     users = SerializedPKRelatedField(
     users = SerializedPKRelatedField(
         queryset=get_user_model().objects.all(),
         queryset=get_user_model().objects.all(),
-        serializer=NestedUserSerializer,
+        serializer=UserSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 12 - 12
netbox/users/api/serializers_/users.py

@@ -6,7 +6,6 @@ from rest_framework import serializers
 
 
 from netbox.api.fields import SerializedPKRelatedField
 from netbox.api.fields import SerializedPKRelatedField
 from netbox.api.serializers import ValidatedModelSerializer
 from netbox.api.serializers import ValidatedModelSerializer
-from ..nested_serializers import *
 
 
 __all__ = (
 __all__ = (
     'GroupSerializer',
     'GroupSerializer',
@@ -14,11 +13,22 @@ __all__ = (
 )
 )
 
 
 
 
+class GroupSerializer(ValidatedModelSerializer):
+    url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')
+    user_count = serializers.IntegerField(read_only=True)
+
+    class Meta:
+        model = Group
+        fields = ('id', 'url', 'display', 'name', 'user_count')
+        brief_fields = ('id', 'url', 'display', 'name')
+
+
 class UserSerializer(ValidatedModelSerializer):
 class UserSerializer(ValidatedModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')
     url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')
     groups = SerializedPKRelatedField(
     groups = SerializedPKRelatedField(
         queryset=Group.objects.all(),
         queryset=Group.objects.all(),
-        serializer=NestedGroupSerializer,
+        serializer=GroupSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -60,13 +70,3 @@ class UserSerializer(ValidatedModelSerializer):
         if full_name := obj.get_full_name():
         if full_name := obj.get_full_name():
             return f"{obj.username} ({full_name})"
             return f"{obj.username} ({full_name})"
         return obj.username
         return obj.username
-
-
-class GroupSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')
-    user_count = serializers.IntegerField(read_only=True)
-
-    class Meta:
-        model = Group
-        fields = ('id', 'url', 'display', 'name', 'user_count')
-        brief_fields = ('id', 'url', 'display', 'name')

+ 4 - 5
netbox/virtualization/api/serializers_/virtualmachines.py

@@ -6,8 +6,7 @@ from dcim.api.serializers_.platforms import PlatformSerializer
 from dcim.api.serializers_.roles import DeviceRoleSerializer
 from dcim.api.serializers_.roles import DeviceRoleSerializer
 from dcim.api.serializers_.sites import SiteSerializer
 from dcim.api.serializers_.sites import SiteSerializer
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
-from extras.api.serializers_.provisioning import ConfigTemplateSerializer
-from ipam.api.nested_serializers import NestedVLANSerializer
+from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
 from ipam.api.serializers_.ip import IPAddressSerializer
 from ipam.api.serializers_.ip import IPAddressSerializer
 from ipam.api.serializers_.vlans import VLANSerializer
 from ipam.api.serializers_.vlans import VLANSerializer
 from ipam.api.serializers_.vrfs import VRFSerializer
 from ipam.api.serializers_.vrfs import VRFSerializer
@@ -18,9 +17,8 @@ from tenancy.api.serializers_.tenants import TenantSerializer
 from virtualization.choices import *
 from virtualization.choices import *
 from virtualization.models import VirtualDisk, VirtualMachine, VMInterface
 from virtualization.models import VirtualDisk, VirtualMachine, VMInterface
 from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
 from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
-from ..nested_serializers import *
-
 from .clusters import ClusterSerializer
 from .clusters import ClusterSerializer
+from ..nested_serializers import *
 
 
 __all__ = (
 __all__ = (
     'VMInterfaceSerializer',
     'VMInterfaceSerializer',
@@ -89,7 +87,8 @@ class VMInterfaceSerializer(NetBoxModelSerializer):
     untagged_vlan = VLANSerializer(nested=True, required=False, allow_null=True)
     untagged_vlan = VLANSerializer(nested=True, required=False, allow_null=True)
     tagged_vlans = SerializedPKRelatedField(
     tagged_vlans = SerializedPKRelatedField(
         queryset=VLAN.objects.all(),
         queryset=VLAN.objects.all(),
-        serializer=NestedVLANSerializer,
+        serializer=VLANSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 4 - 3
netbox/vpn/api/serializers_/crypto.py

@@ -4,7 +4,6 @@ from netbox.api.fields import ChoiceField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
 from vpn.choices import *
 from vpn.choices import *
 from vpn.models import IKEPolicy, IKEProposal, IPSecPolicy, IPSecProfile, IPSecProposal
 from vpn.models import IKEPolicy, IKEProposal, IPSecPolicy, IPSecProfile, IPSecProposal
-from ..nested_serializers import *
 
 
 __all__ = (
 __all__ = (
     'IKEPolicySerializer',
     'IKEPolicySerializer',
@@ -54,7 +53,8 @@ class IKEPolicySerializer(NetBoxModelSerializer):
     )
     )
     proposals = SerializedPKRelatedField(
     proposals = SerializedPKRelatedField(
         queryset=IKEProposal.objects.all(),
         queryset=IKEProposal.objects.all(),
-        serializer=NestedIKEProposalSerializer,
+        serializer=IKEProposalSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
@@ -94,7 +94,8 @@ class IPSecPolicySerializer(NetBoxModelSerializer):
     )
     )
     proposals = SerializedPKRelatedField(
     proposals = SerializedPKRelatedField(
         queryset=IPSecProposal.objects.all(),
         queryset=IPSecProposal.objects.all(),
-        serializer=NestedIPSecProposalSerializer,
+        serializer=IPSecProposalSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )

+ 5 - 3
netbox/vpn/api/serializers_/l2vpn.py

@@ -2,7 +2,7 @@ from django.contrib.contenttypes.models import ContentType
 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 ipam.api.nested_serializers import NestedRouteTargetSerializer
+from ipam.api.serializers_.vrfs import RouteTargetSerializer
 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, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
 from netbox.api.serializers import NetBoxModelSerializer
@@ -23,13 +23,15 @@ class L2VPNSerializer(NetBoxModelSerializer):
     type = ChoiceField(choices=L2VPNTypeChoices, required=False)
     type = ChoiceField(choices=L2VPNTypeChoices, required=False)
     import_targets = SerializedPKRelatedField(
     import_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        serializer=NestedRouteTargetSerializer,
+        serializer=RouteTargetSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )
     export_targets = SerializedPKRelatedField(
     export_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        serializer=NestedRouteTargetSerializer,
+        serializer=RouteTargetSerializer,
+        nested=True,
         required=False,
         required=False,
         many=True
         many=True
     )
     )