Переглянути джерело

Closes #17143: Deprecate the use of dedicated nested API serializers

Jeremy Stretch 1 рік тому
батько
коміт
e3d681be54
40 змінених файлів з 345 додано та 217 видалено
  1. 9 12
      netbox/circuits/api/nested_serializers.py
  2. 0 1
      netbox/circuits/api/serializers.py
  3. 13 0
      netbox/circuits/api/serializers_/nested.py
  4. 1 1
      netbox/circuits/api/serializers_/providers.py
  5. 8 0
      netbox/core/api/nested_serializers.py
  6. 0 1
      netbox/core/api/serializers.py
  7. 12 82
      netbox/dcim/api/nested_serializers.py
  8. 0 1
      netbox/dcim/api/serializers.py
  9. 2 2
      netbox/dcim/api/serializers_/device_components.py
  10. 1 1
      netbox/dcim/api/serializers_/devices.py
  11. 1 1
      netbox/dcim/api/serializers_/devicetype_components.py
  12. 98 0
      netbox/dcim/api/serializers_/nested.py
  13. 1 1
      netbox/dcim/api/serializers_/sites.py
  14. 1 1
      netbox/dcim/api/serializers_/virtualchassis.py
  15. 8 0
      netbox/extras/api/nested_serializers.py
  16. 0 1
      netbox/extras/api/serializers.py
  17. 9 13
      netbox/ipam/api/nested_serializers.py
  18. 0 1
      netbox/ipam/api/serializers.py
  19. 1 1
      netbox/ipam/api/serializers_/ip.py
  20. 18 0
      netbox/ipam/api/serializers_/nested.py
  21. 1 1
      netbox/netbox/api/serializers/nested.py
  22. 8 26
      netbox/tenancy/api/nested_serializers.py
  23. 0 1
      netbox/tenancy/api/serializers.py
  24. 1 1
      netbox/tenancy/api/serializers_/contacts.py
  25. 34 0
      netbox/tenancy/api/serializers_/nested.py
  26. 1 1
      netbox/tenancy/api/serializers_/tenants.py
  27. 9 21
      netbox/users/api/nested_serializers.py
  28. 0 1
      netbox/users/api/serializers.py
  29. 30 0
      netbox/users/api/serializers_/nested.py
  30. 1 3
      netbox/users/api/serializers_/permissions.py
  31. 10 17
      netbox/virtualization/api/nested_serializers.py
  32. 0 1
      netbox/virtualization/api/serializers.py
  33. 22 0
      netbox/virtualization/api/serializers_/nested.py
  34. 1 1
      netbox/virtualization/api/serializers_/virtualmachines.py
  35. 8 1
      netbox/vpn/api/nested_serializers.py
  36. 0 1
      netbox/vpn/api/serializers.py
  37. 6 19
      netbox/wireless/api/nested_serializers.py
  38. 0 1
      netbox/wireless/api/serializers.py
  39. 29 0
      netbox/wireless/api/serializers_/nested.py
  40. 1 1
      netbox/wireless/api/serializers_/wirelesslans.py

+ 9 - 12
netbox/circuits/api/nested_serializers.py

@@ -1,9 +1,11 @@
+import warnings
+
 from drf_spectacular.utils import extend_schema_serializer
-from rest_framework import serializers
 
 from circuits.models import *
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import WritableNestedSerializer
+from .serializers_.nested import NestedProviderAccountSerializer
 
 __all__ = [
     'NestedCircuitSerializer',
@@ -14,6 +16,12 @@ __all__ = [
     'NestedProviderAccountSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 #
 # Provider networks
@@ -41,17 +49,6 @@ class NestedProviderSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'circuit_count']
 
 
-#
-# Provider Accounts
-#
-
-class NestedProviderAccountSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = ProviderAccount
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'account']
-
-
 #
 # Circuits
 #

+ 0 - 1
netbox/circuits/api/serializers.py

@@ -1,3 +1,2 @@
 from .serializers_.providers import *
 from .serializers_.circuits import *
-from .nested_serializers import *

+ 13 - 0
netbox/circuits/api/serializers_/nested.py

@@ -0,0 +1,13 @@
+from circuits.models import ProviderAccount
+from netbox.api.serializers import WritableNestedSerializer
+
+__all__ = (
+    'NestedProviderAccountSerializer',
+)
+
+
+class NestedProviderAccountSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = ProviderAccount
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'account']

+ 1 - 1
netbox/circuits/api/serializers_/providers.py

@@ -5,7 +5,7 @@ from ipam.api.serializers_.asns import ASNSerializer
 from ipam.models import ASN
 from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.serializers import NetBoxModelSerializer
-from ..nested_serializers import *
+from .nested import NestedProviderAccountSerializer
 
 __all__ = (
     'ProviderAccountSerializer',

+ 8 - 0
netbox/core/api/nested_serializers.py

@@ -1,3 +1,5 @@
+import warnings
+
 from rest_framework import serializers
 
 from core.choices import JobStatusChoices
@@ -12,6 +14,12 @@ __all__ = (
     'NestedJobSerializer',
 )
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 class NestedDataSourceSerializer(WritableNestedSerializer):
 

+ 0 - 1
netbox/core/api/serializers.py

@@ -1,4 +1,3 @@
 from .serializers_.change_logging import *
 from .serializers_.data import *
 from .serializers_.jobs import *
-from .nested_serializers import *

+ 12 - 82
netbox/dcim/api/nested_serializers.py

@@ -1,9 +1,15 @@
+import warnings
+
 from drf_spectacular.utils import extend_schema_serializer
 from rest_framework import serializers
 
 from dcim import models
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import WritableNestedSerializer
+from .serializers_.nested import (
+    NestedDeviceBaySerializer, NestedDeviceSerializer, NestedInterfaceSerializer, NestedInterfaceTemplateSerializer,
+    NestedLocationSerializer, NestedModuleBaySerializer, NestedRegionSerializer, NestedSiteGroupSerializer,
+)
 
 __all__ = [
     'NestedCableSerializer',
@@ -48,35 +54,17 @@ __all__ = [
     'NestedVirtualDeviceContextSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 #
 # Regions/sites
 #
 
-@extend_schema_serializer(
-    exclude_fields=('site_count',),
-)
-class NestedRegionSerializer(WritableNestedSerializer):
-    site_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = models.Region
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
-
-
-@extend_schema_serializer(
-    exclude_fields=('site_count',),
-)
-class NestedSiteGroupSerializer(WritableNestedSerializer):
-    site_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = models.SiteGroup
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
-
-
 class NestedSiteSerializer(WritableNestedSerializer):
 
     class Meta:
@@ -88,18 +76,6 @@ class NestedSiteSerializer(WritableNestedSerializer):
 # Racks
 #
 
-@extend_schema_serializer(
-    exclude_fields=('rack_count',),
-)
-class NestedLocationSerializer(WritableNestedSerializer):
-    rack_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = models.Location
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth']
-
-
 @extend_schema_serializer(
     exclude_fields=('rack_count',),
 )
@@ -200,13 +176,6 @@ class NestedPowerOutletTemplateSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
-class NestedInterfaceTemplateSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = models.InterfaceTemplate
-        fields = ['id', 'url', 'display_url', 'display', 'name']
-
-
 class NestedRearPortTemplateSerializer(WritableNestedSerializer):
 
     class Meta:
@@ -271,13 +240,6 @@ class NestedPlatformSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'device_count', 'virtualmachine_count']
 
 
-class NestedDeviceSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = models.Device
-        fields = ['id', 'url', 'display_url', 'display', 'name']
-
-
 class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
 
     class Meta:
@@ -285,13 +247,6 @@ class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
-class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = models.Module
-        fields = ['id', 'url', 'display_url', 'display', 'serial']
-
-
 class NestedModuleSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     module_bay = ModuleNestedModuleBaySerializer(read_only=True)
@@ -338,15 +293,6 @@ class NestedPowerPortSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
-class NestedInterfaceSerializer(WritableNestedSerializer):
-    device = NestedDeviceSerializer(read_only=True)
-    _occupied = serializers.BooleanField(required=False, read_only=True)
-
-    class Meta:
-        model = models.Interface
-        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
-
-
 class NestedRearPortSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
@@ -365,22 +311,6 @@ class NestedFrontPortSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
-class NestedModuleBaySerializer(WritableNestedSerializer):
-    installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)
-
-    class Meta:
-        model = models.ModuleBay
-        fields = ['id', 'url', 'display_url', 'display', 'installed_module', 'name']
-
-
-class NestedDeviceBaySerializer(WritableNestedSerializer):
-    device = NestedDeviceSerializer(read_only=True)
-
-    class Meta:
-        model = models.DeviceBay
-        fields = ['id', 'url', 'display_url', 'display', 'device', 'name']
-
-
 class NestedInventoryItemSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)

+ 0 - 1
netbox/dcim/api/serializers.py

@@ -11,4 +11,3 @@ from .serializers_.devices import *
 from .serializers_.device_components import *
 from .serializers_.power import *
 from .serializers_.rackunits import *
-from .nested_serializers import *

+ 2 - 2
netbox/dcim/api/serializers_/device_components.py

@@ -15,7 +15,7 @@ from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelated
 from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
 from utilities.api import get_serializer_for_model
 from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
-from wireless.api.nested_serializers import NestedWirelessLinkSerializer
+from wireless.api.serializers_.nested import NestedWirelessLinkSerializer
 from wireless.api.serializers_.wirelesslans import WirelessLANSerializer
 from wireless.choices import *
 from wireless.models import WirelessLAN
@@ -23,8 +23,8 @@ from .base import ConnectedEndpointsSerializer
 from .cables import CabledObjectSerializer
 from .devices import DeviceSerializer, ModuleSerializer, VirtualDeviceContextSerializer
 from .manufacturers import ManufacturerSerializer
+from .nested import NestedInterfaceSerializer
 from .roles import InventoryItemRoleSerializer
-from ..nested_serializers import *
 
 __all__ = (
     'ConsolePortSerializer',

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

@@ -16,9 +16,9 @@ from .devicetypes import *
 from .platforms import PlatformSerializer
 from .racks import RackSerializer
 from .roles import DeviceRoleSerializer
+from .nested import NestedDeviceBaySerializer, NestedDeviceSerializer, NestedModuleBaySerializer
 from .sites import LocationSerializer, SiteSerializer
 from .virtualchassis import VirtualChassisSerializer
-from ..nested_serializers import *
 
 __all__ = (
     'DeviceSerializer',

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

@@ -14,8 +14,8 @@ from utilities.api import get_serializer_for_model
 from wireless.choices import *
 from .devicetypes import DeviceTypeSerializer, ModuleTypeSerializer
 from .manufacturers import ManufacturerSerializer
+from .nested import NestedInterfaceTemplateSerializer
 from .roles import InventoryItemRoleSerializer
-from ..nested_serializers import *
 
 __all__ = (
     'ConsolePortTemplateSerializer',

+ 98 - 0
netbox/dcim/api/serializers_/nested.py

@@ -0,0 +1,98 @@
+from drf_spectacular.utils import extend_schema_serializer
+from rest_framework import serializers
+
+from netbox.api.serializers import WritableNestedSerializer
+from dcim import models
+
+__all__ = (
+    'NestedDeviceBaySerializer',
+    'NestedDeviceSerializer',
+    'NestedInterfaceSerializer',
+    'NestedInterfaceTemplateSerializer',
+    'NestedLocationSerializer',
+    'NestedModuleBaySerializer',
+    'NestedRegionSerializer',
+    'NestedSiteGroupSerializer',
+)
+
+
+@extend_schema_serializer(
+    exclude_fields=('site_count',),
+)
+class NestedRegionSerializer(WritableNestedSerializer):
+    site_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.Region
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
+
+
+@extend_schema_serializer(
+    exclude_fields=('site_count',),
+)
+class NestedSiteGroupSerializer(WritableNestedSerializer):
+    site_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.SiteGroup
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
+
+
+@extend_schema_serializer(
+    exclude_fields=('rack_count',),
+)
+class NestedLocationSerializer(WritableNestedSerializer):
+    rack_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.Location
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth']
+
+
+class NestedDeviceSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.Device
+        fields = ['id', 'url', 'display_url', 'display', 'name']
+
+
+class NestedInterfaceSerializer(WritableNestedSerializer):
+    device = NestedDeviceSerializer(read_only=True)
+    _occupied = serializers.BooleanField(required=False, read_only=True)
+
+    class Meta:
+        model = models.Interface
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
+
+
+class NestedInterfaceTemplateSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.InterfaceTemplate
+        fields = ['id', 'url', 'display_url', 'display', 'name']
+
+
+class NestedDeviceBaySerializer(WritableNestedSerializer):
+    device = NestedDeviceSerializer(read_only=True)
+
+    class Meta:
+        model = models.DeviceBay
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name']
+
+
+class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.Module
+        fields = ['id', 'url', 'display_url', 'display', 'serial']
+
+
+class NestedModuleBaySerializer(WritableNestedSerializer):
+    installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)
+
+    class Meta:
+        model = models.ModuleBay
+        fields = ['id', 'url', 'display_url', 'display', 'installed_module', 'name']

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

@@ -8,7 +8,7 @@ from ipam.models import ASN
 from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
 from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
-from ..nested_serializers import *
+from .nested import NestedLocationSerializer, NestedRegionSerializer, NestedSiteGroupSerializer
 
 __all__ = (
     'LocationSerializer',

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

@@ -2,7 +2,7 @@ from rest_framework import serializers
 
 from dcim.models import VirtualChassis
 from netbox.api.serializers import NetBoxModelSerializer
-from ..nested_serializers import *
+from .nested import NestedDeviceSerializer
 
 __all__ = (
     'VirtualChassisSerializer',

+ 8 - 0
netbox/extras/api/nested_serializers.py

@@ -1,3 +1,5 @@
+import warnings
+
 from rest_framework import serializers
 
 from extras import models
@@ -20,6 +22,12 @@ __all__ = [
     'NestedWebhookSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 class NestedEventRuleSerializer(WritableNestedSerializer):
 

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

@@ -13,4 +13,3 @@ from .serializers_.configtemplates import *
 from .serializers_.savedfilters import *
 from .serializers_.scripts import *
 from .serializers_.tags import *
-from .nested_serializers import *

+ 9 - 13
netbox/ipam/api/nested_serializers.py

@@ -1,3 +1,5 @@
+import warnings
+
 from drf_spectacular.utils import extend_schema_serializer
 from rest_framework import serializers
 
@@ -5,6 +7,7 @@ from ipam import models
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import WritableNestedSerializer
 from .field_serializers import IPAddressField
+from .serializers_.nested import NestedIPAddressSerializer
 
 __all__ = [
     'NestedAggregateSerializer',
@@ -25,6 +28,12 @@ __all__ = [
     'NestedVRFSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 #
 # ASN ranges
@@ -177,19 +186,6 @@ class NestedIPRangeSerializer(WritableNestedSerializer):
         fields = ['id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address']
 
 
-#
-# IP addresses
-#
-
-class NestedIPAddressSerializer(WritableNestedSerializer):
-    family = serializers.IntegerField(read_only=True)
-    address = IPAddressField()
-
-    class Meta:
-        model = models.IPAddress
-        fields = ['id', 'url', 'display_url', 'display', 'family', 'address']
-
-
 #
 # Services
 #

+ 0 - 1
netbox/ipam/api/serializers.py

@@ -5,4 +5,3 @@ from .serializers_.vlans import *
 from .serializers_.ip import *
 from .serializers_.fhrpgroups import *
 from .serializers_.services import *
-from .nested_serializers import *

+ 1 - 1
netbox/ipam/api/serializers_/ip.py

@@ -11,11 +11,11 @@ from netbox.api.serializers import NetBoxModelSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
 from utilities.api import get_serializer_for_model
 from .asns import RIRSerializer
+from .nested import NestedIPAddressSerializer
 from .roles import RoleSerializer
 from .vlans import VLANSerializer
 from .vrfs import VRFSerializer
 from ..field_serializers import IPAddressField, IPNetworkField
-from ..nested_serializers import *
 
 __all__ = (
     'AggregateSerializer',

+ 18 - 0
netbox/ipam/api/serializers_/nested.py

@@ -0,0 +1,18 @@
+from rest_framework import serializers
+
+from ipam import models
+from netbox.api.serializers import WritableNestedSerializer
+from ..field_serializers import IPAddressField
+
+__all__ = (
+    'NestedIPAddressSerializer',
+)
+
+
+class NestedIPAddressSerializer(WritableNestedSerializer):
+    family = serializers.IntegerField(read_only=True)
+    address = IPAddressField()
+
+    class Meta:
+        model = models.IPAddress
+        fields = ['id', 'url', 'display_url', 'display', 'family', 'address']

+ 1 - 1
netbox/netbox/api/serializers/nested.py

@@ -21,7 +21,7 @@ class WritableNestedSerializer(BaseModelSerializer):
         return get_related_object_by_attrs(queryset, data)
 
 
-# Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
+# Declared here for use by PrimaryModelSerializer
 class NestedTagSerializer(WritableNestedSerializer):
 
     class Meta:

+ 8 - 26
netbox/tenancy/api/nested_serializers.py

@@ -1,7 +1,7 @@
-from drf_spectacular.utils import extend_schema_serializer
-from rest_framework import serializers
+import warnings
 
 from netbox.api.serializers import WritableNestedSerializer
+from serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer
 from tenancy.models import *
 
 __all__ = [
@@ -13,23 +13,17 @@ __all__ = [
     'NestedTenantSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 #
 # Tenants
 #
 
-@extend_schema_serializer(
-    exclude_fields=('tenant_count',),
-)
-class NestedTenantGroupSerializer(WritableNestedSerializer):
-    tenant_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = TenantGroup
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'tenant_count', '_depth']
-
-
 class NestedTenantSerializer(WritableNestedSerializer):
 
     class Meta:
@@ -41,18 +35,6 @@ class NestedTenantSerializer(WritableNestedSerializer):
 # Contacts
 #
 
-@extend_schema_serializer(
-    exclude_fields=('contact_count',),
-)
-class NestedContactGroupSerializer(WritableNestedSerializer):
-    contact_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = ContactGroup
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'contact_count', '_depth']
-
-
 class NestedContactRoleSerializer(WritableNestedSerializer):
 
     class Meta:

+ 0 - 1
netbox/tenancy/api/serializers.py

@@ -1,3 +1,2 @@
 from .serializers_.tenants import *
 from .serializers_.contacts import *
-from .nested_serializers import *

+ 1 - 1
netbox/tenancy/api/serializers_/contacts.py

@@ -8,7 +8,7 @@ from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerial
 from tenancy.choices import ContactPriorityChoices
 from tenancy.models import ContactAssignment, Contact, ContactGroup, ContactRole
 from utilities.api import get_serializer_for_model
-from ..nested_serializers import *
+from .nested import NestedContactGroupSerializer
 
 __all__ = (
     'ContactAssignmentSerializer',

+ 34 - 0
netbox/tenancy/api/serializers_/nested.py

@@ -0,0 +1,34 @@
+from drf_spectacular.utils import extend_schema_serializer
+from rest_framework import serializers
+
+from netbox.api.serializers import WritableNestedSerializer
+from tenancy import models
+
+__all__ = (
+    'NestedContactGroupSerializer',
+    'NestedTenantGroupSerializer',
+)
+
+
+@extend_schema_serializer(
+    exclude_fields=('contact_count',),
+)
+class NestedContactGroupSerializer(WritableNestedSerializer):
+    contact_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.ContactGroup
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'contact_count', '_depth']
+
+
+@extend_schema_serializer(
+    exclude_fields=('tenant_count',),
+)
+class NestedTenantGroupSerializer(WritableNestedSerializer):
+    tenant_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.TenantGroup
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'tenant_count', '_depth']

+ 1 - 1
netbox/tenancy/api/serializers_/tenants.py

@@ -3,7 +3,7 @@ from rest_framework import serializers
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
 from tenancy.models import Tenant, TenantGroup
-from ..nested_serializers import *
+from .nested import NestedTenantGroupSerializer
 
 __all__ = (
     'TenantGroupSerializer',

+ 9 - 21
netbox/users/api/nested_serializers.py

@@ -1,11 +1,13 @@
-from drf_spectacular.types import OpenApiTypes
+import warnings
+
 from drf_spectacular.utils import extend_schema_field
 from rest_framework import serializers
 
 from core.models import ObjectType
 from netbox.api.fields import ContentTypeField
 from netbox.api.serializers import WritableNestedSerializer
-from users.models import Group, ObjectPermission, Token, User
+from serializers_.nested import NestedGroupSerializer, NestedUserSerializer
+from users.models import ObjectPermission, Token
 
 __all__ = [
     'NestedGroupSerializer',
@@ -14,25 +16,11 @@ __all__ = [
     'NestedUserSerializer',
 ]
 
-
-class NestedGroupSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = Group
-        fields = ['id', 'url', 'display_url', 'display', 'name']
-
-
-class NestedUserSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = User
-        fields = ['id', 'url', 'display_url', 'display', 'username']
-
-    @extend_schema_field(OpenApiTypes.STR)
-    def get_display(self, obj):
-        if full_name := obj.get_full_name():
-            return f"{obj.username} ({full_name})"
-        return obj.username
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
 
 
 class NestedTokenSerializer(WritableNestedSerializer):

+ 0 - 1
netbox/users/api/serializers.py

@@ -1,4 +1,3 @@
 from .serializers_.users import *
 from .serializers_.permissions import *
 from .serializers_.tokens import *
-from .nested_serializers import *

+ 30 - 0
netbox/users/api/serializers_/nested.py

@@ -0,0 +1,30 @@
+from drf_spectacular.types import OpenApiTypes
+from drf_spectacular.utils import extend_schema_field
+
+from netbox.api.serializers import WritableNestedSerializer
+from users import models
+
+__all__ = (
+    'NestedGroupSerializer',
+    'NestedUserSerializer',
+)
+
+
+class NestedGroupSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.Group
+        fields = ['id', 'url', 'display_url', 'display', 'name']
+
+
+class NestedUserSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.User
+        fields = ['id', 'url', 'display_url', 'display', 'username']
+
+    @extend_schema_field(OpenApiTypes.STR)
+    def get_display(self, obj):
+        if full_name := obj.get_full_name():
+            return f"{obj.username} ({full_name})"
+        return obj.username

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

@@ -1,10 +1,8 @@
-from rest_framework import serializers
-
 from core.models import ObjectType
 from netbox.api.fields import ContentTypeField, SerializedPKRelatedField
 from netbox.api.serializers import ValidatedModelSerializer
-from users.api.nested_serializers import NestedGroupSerializer, NestedUserSerializer
 from users.models import Group, ObjectPermission, User
+from .nested import NestedGroupSerializer, NestedUserSerializer
 
 __all__ = (
     'ObjectPermissionSerializer',

+ 10 - 17
netbox/virtualization/api/nested_serializers.py

@@ -1,9 +1,11 @@
+import warnings
+
 from drf_spectacular.utils import extend_schema_serializer
-from rest_framework import serializers
 
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import WritableNestedSerializer
 from virtualization.models import *
+from .serializers_.nested import NestedVirtualMachineSerializer, NestedVMInterfaceSerializer
 
 __all__ = [
     'NestedClusterGroupSerializer',
@@ -14,11 +16,17 @@ __all__ = [
     'NestedVirtualMachineSerializer',
 ]
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
+
 #
 # Clusters
 #
 
-
 @extend_schema_serializer(
     exclude_fields=('cluster_count',),
 )
@@ -56,21 +64,6 @@ class NestedClusterSerializer(WritableNestedSerializer):
 # Virtual machines
 #
 
-class NestedVirtualMachineSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = VirtualMachine
-        fields = ['id', 'url', 'display_url', 'display', 'name']
-
-
-class NestedVMInterfaceSerializer(WritableNestedSerializer):
-    virtual_machine = NestedVirtualMachineSerializer(read_only=True)
-
-    class Meta:
-        model = VMInterface
-        fields = ['id', 'url', 'display_url', 'display', 'virtual_machine', 'name']
-
-
 class NestedVirtualDiskSerializer(WritableNestedSerializer):
     virtual_machine = NestedVirtualMachineSerializer(read_only=True)
 

+ 0 - 1
netbox/virtualization/api/serializers.py

@@ -1,3 +1,2 @@
 from .serializers_.clusters import *
 from .serializers_.virtualmachines import *
-from .nested_serializers import *

+ 22 - 0
netbox/virtualization/api/serializers_/nested.py

@@ -0,0 +1,22 @@
+from netbox.api.serializers import WritableNestedSerializer
+from virtualization import models
+
+__all__ = (
+    'NestedVirtualMachineSerializer',
+    'NestedVMInterfaceSerializer',
+)
+
+
+class NestedVirtualMachineSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.VirtualMachine
+        fields = ['id', 'url', 'display_url', 'display', 'name']
+
+
+class NestedVMInterfaceSerializer(WritableNestedSerializer):
+    virtual_machine = NestedVirtualMachineSerializer(read_only=True)
+
+    class Meta:
+        model = models.VMInterface
+        fields = ['id', 'url', 'display_url', 'display', 'virtual_machine', 'name']

+ 1 - 1
netbox/virtualization/api/serializers_/virtualmachines.py

@@ -18,7 +18,7 @@ from virtualization.choices import *
 from virtualization.models import VirtualDisk, VirtualMachine, VMInterface
 from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
 from .clusters import ClusterSerializer
-from ..nested_serializers import *
+from .nested import NestedVMInterfaceSerializer
 
 __all__ = (
     'VMInterfaceSerializer',

+ 8 - 1
netbox/vpn/api/nested_serializers.py

@@ -1,5 +1,6 @@
+import warnings
+
 from drf_spectacular.utils import extend_schema_serializer
-from rest_framework import serializers
 
 from netbox.api.fields import RelatedObjectCountField
 from netbox.api.serializers import WritableNestedSerializer
@@ -18,6 +19,12 @@ __all__ = (
     'NestedTunnelTerminationSerializer',
 )
 
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
+)
+
 
 @extend_schema_serializer(
     exclude_fields=('tunnel_count',),

+ 0 - 1
netbox/vpn/api/serializers.py

@@ -1,4 +1,3 @@
 from .serializers_.crypto import *
 from .serializers_.tunnels import *
 from .serializers_.l2vpn import *
-from .nested_serializers import *

+ 6 - 19
netbox/wireless/api/nested_serializers.py

@@ -1,8 +1,8 @@
-from drf_spectacular.utils import extend_schema_serializer
-from rest_framework import serializers
+import warnings
 
 from netbox.api.serializers import WritableNestedSerializer
 from wireless.models import *
+from .serializers_.nested import NestedWirelessLANGroupSerializer, NestedWirelessLinkSerializer
 
 __all__ = (
     'NestedWirelessLANSerializer',
@@ -10,17 +10,11 @@ __all__ = (
     'NestedWirelessLinkSerializer',
 )
 
-
-@extend_schema_serializer(
-    exclude_fields=('wirelesslan_count',),
+# TODO: Remove in v4.2
+warnings.warn(
+    f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.",
+    DeprecationWarning
 )
-class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
-    wirelesslan_count = serializers.IntegerField(read_only=True)
-    _depth = serializers.IntegerField(source='level', read_only=True)
-
-    class Meta:
-        model = WirelessLANGroup
-        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'wirelesslan_count', '_depth']
 
 
 class NestedWirelessLANSerializer(WritableNestedSerializer):
@@ -28,10 +22,3 @@ class NestedWirelessLANSerializer(WritableNestedSerializer):
     class Meta:
         model = WirelessLAN
         fields = ['id', 'url', 'display_url', 'display', 'ssid']
-
-
-class NestedWirelessLinkSerializer(WritableNestedSerializer):
-
-    class Meta:
-        model = WirelessLink
-        fields = ['id', 'url', 'display_url', 'display', 'ssid']

+ 0 - 1
netbox/wireless/api/serializers.py

@@ -1,3 +1,2 @@
 from .serializers_.wirelesslans import *
 from .serializers_.wirelesslinks import *
-from .nested_serializers import *

+ 29 - 0
netbox/wireless/api/serializers_/nested.py

@@ -0,0 +1,29 @@
+from drf_spectacular.utils import extend_schema_serializer
+from rest_framework import serializers
+
+from netbox.api.serializers import WritableNestedSerializer
+from wireless import models
+
+__all__ = (
+    'NestedWirelessLANGroupSerializer',
+    'NestedWirelessLinkSerializer',
+)
+
+
+@extend_schema_serializer(
+    exclude_fields=('wirelesslan_count',),
+)
+class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
+    wirelesslan_count = serializers.IntegerField(read_only=True)
+    _depth = serializers.IntegerField(source='level', read_only=True)
+
+    class Meta:
+        model = models.WirelessLANGroup
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'wirelesslan_count', '_depth']
+
+
+class NestedWirelessLinkSerializer(WritableNestedSerializer):
+
+    class Meta:
+        model = models.WirelessLink
+        fields = ['id', 'url', 'display_url', 'display', 'ssid']

+ 1 - 1
netbox/wireless/api/serializers_/wirelesslans.py

@@ -6,7 +6,7 @@ from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerial
 from tenancy.api.serializers_.tenants import TenantSerializer
 from wireless.choices import *
 from wireless.models import WirelessLAN, WirelessLANGroup
-from ..nested_serializers import *
+from .nested import NestedWirelessLANGroupSerializer
 
 __all__ = (
     'WirelessLANGroupSerializer',