From 7b5349e1dc4c17a05600629b1be0039e0878caa0 Mon Sep 17 00:00:00 2001 From: Brian Tiemann Date: Wed, 29 Oct 2025 16:03:23 -0400 Subject: [PATCH] Apply GFKSerializerField to all matching SerializerMethodFields --- contrib/openapi.json | 77 +++++++++---------- netbox/circuits/api/serializers_/circuits.py | 2 +- netbox/dcim/api/serializers_/cables.py | 11 +-- .../api/serializers_/device_components.py | 13 +--- netbox/dcim/api/serializers_/devices.py | 12 +-- .../api/serializers_/devicetype_components.py | 13 +--- netbox/extras/api/serializers_/attachments.py | 11 +-- netbox/extras/api/serializers_/bookmarks.py | 13 +--- netbox/extras/api/serializers_/journaling.py | 11 +-- .../extras/api/serializers_/notifications.py | 21 +---- netbox/ipam/api/serializers_/fhrpgroups.py | 15 +--- netbox/ipam/api/serializers_/ip.py | 23 +----- netbox/ipam/api/serializers_/services.py | 14 +--- netbox/ipam/api/serializers_/vlans.py | 13 +--- .../netbox/api/{fields2.py => gfk_fields.py} | 0 netbox/tenancy/api/serializers_/contacts.py | 12 +-- .../api/serializers_/clusters.py | 13 +--- netbox/vpn/api/serializers_/l2vpn.py | 12 +-- netbox/vpn/api/serializers_/tunnels.py | 16 +--- .../wireless/api/serializers_/wirelesslans.py | 13 +--- 20 files changed, 75 insertions(+), 240 deletions(-) rename netbox/netbox/api/{fields2.py => gfk_fields.py} (100%) diff --git a/contrib/openapi.json b/contrib/openapi.json index c5d0db25c..9c2a601c2 100644 --- a/contrib/openapi.json +++ b/contrib/openapi.json @@ -206935,8 +206935,8 @@ "format": "int64" }, "object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "user": { "$ref": "#/components/schemas/BriefUser" @@ -211700,8 +211700,8 @@ "readOnly": true }, "termination": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "created": { "type": "string", @@ -212978,8 +212978,8 @@ "nullable": true }, "scope": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "description": { "type": "string", @@ -215293,9 +215293,8 @@ "format": "int64" }, "object": { - "type": "object", - "additionalProperties": {}, - "readOnly": true + "readOnly": true, + "nullable": true }, "contact": { "$ref": "#/components/schemas/BriefContact" @@ -219536,8 +219535,8 @@ "format": "int64" }, "interface": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "priority": { "type": "integer", @@ -221339,8 +221338,8 @@ "nullable": true }, "assigned_object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "nat_inside": { "allOf": [ @@ -222501,8 +222500,8 @@ "format": "int64" }, "parent": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "name": { "type": "string", @@ -225660,8 +225659,8 @@ "nullable": true }, "component": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "tags": { "type": "array", @@ -226044,8 +226043,8 @@ "nullable": true }, "component": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "created": { "type": "string", @@ -226327,8 +226326,8 @@ "format": "int64" }, "assigned_object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "created": { "type": "string", @@ -226777,8 +226776,8 @@ "format": "int64" }, "assigned_object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "tags": { "type": "array", @@ -227155,8 +227154,8 @@ "nullable": true }, "assigned_object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "description": { "type": "string", @@ -229542,8 +229541,8 @@ "format": "int64" }, "object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "user": { "$ref": "#/components/schemas/BriefUser" @@ -248892,8 +248891,8 @@ "nullable": true }, "scope": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "tenant": { "allOf": [ @@ -252745,8 +252744,8 @@ "format": "int64" }, "parent": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "name": { "type": "string", @@ -253669,8 +253668,8 @@ "format": "int64" }, "object": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "user": { "$ref": "#/components/schemas/BriefUser" @@ -255193,8 +255192,8 @@ "nullable": true }, "termination": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "outside_ip": { "allOf": [ @@ -255671,8 +255670,8 @@ "nullable": true }, "scope": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "vid_ranges": { "type": "array", @@ -258528,8 +258527,8 @@ "nullable": true }, "scope": { - "nullable": true, - "readOnly": true + "readOnly": true, + "nullable": true }, "tenant": { "allOf": [ diff --git a/netbox/circuits/api/serializers_/circuits.py b/netbox/circuits/api/serializers_/circuits.py index b0a6f45ce..79e50da28 100644 --- a/netbox/circuits/api/serializers_/circuits.py +++ b/netbox/circuits/api/serializers_/circuits.py @@ -10,7 +10,7 @@ from circuits.models import ( from dcim.api.serializers_.device_components import InterfaceSerializer from dcim.api.serializers_.cables import CabledObjectSerializer from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField -from netbox.api.fields2 import GFKSerializerField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ( NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer, WritableNestedSerializer, ) diff --git a/netbox/dcim/api/serializers_/cables.py b/netbox/dcim/api/serializers_/cables.py index d72b0cbec..5f3017368 100644 --- a/netbox/dcim/api/serializers_/cables.py +++ b/netbox/dcim/api/serializers_/cables.py @@ -5,6 +5,7 @@ from rest_framework import serializers from dcim.choices import * from dcim.models import Cable, CablePath, CableTermination from netbox.api.fields import ChoiceField, ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ( BaseModelSerializer, GenericObjectSerializer, NetBoxModelSerializer, PrimaryModelSerializer, ) @@ -53,9 +54,7 @@ class CableTerminationSerializer(NetBoxModelSerializer): termination_type = ContentTypeField( read_only=True, ) - termination = serializers.SerializerMethodField( - read_only=True, - ) + termination = GFKSerializerField(read_only=True) class Meta: model = CableTermination @@ -66,12 +65,6 @@ class CableTerminationSerializer(NetBoxModelSerializer): read_only_fields = fields brief_fields = ('id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id') - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_termination(self, obj): - serializer = get_serializer_for_model(obj.termination) - context = {'request': self.context['request']} - return serializer(obj.termination, nested=True, context=context).data - class CablePathSerializer(serializers.ModelSerializer): path = serializers.SerializerMethodField(read_only=True) diff --git a/netbox/dcim/api/serializers_/device_components.py b/netbox/dcim/api/serializers_/device_components.py index 468d75af9..b26cf9bbb 100644 --- a/netbox/dcim/api/serializers_/device_components.py +++ b/netbox/dcim/api/serializers_/device_components.py @@ -1,6 +1,5 @@ from django.utils.translation import gettext as _ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from dcim.choices import * @@ -13,8 +12,8 @@ from ipam.api.serializers_.vlans import VLANSerializer, VLANTranslationPolicySer from ipam.api.serializers_.vrfs import VRFSerializer from ipam.models import VLAN from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField +from netbox.api.gfk_fields import GFKSerializerField 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.serializers_.nested import NestedWirelessLinkSerializer from wireless.api.serializers_.wirelesslans import WirelessLANSerializer @@ -394,7 +393,7 @@ class InventoryItemSerializer(NetBoxModelSerializer): required=False, allow_null=True ) - component = serializers.SerializerMethodField(read_only=True, allow_null=True) + component = GFKSerializerField(read_only=True) _depth = serializers.IntegerField(source='level', read_only=True) status = ChoiceField(choices=InventoryItemStatusChoices, required=False) @@ -406,11 +405,3 @@ class InventoryItemSerializer(NetBoxModelSerializer): 'component_id', 'component', 'tags', 'custom_fields', 'created', 'last_updated', '_depth', ] brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', '_depth') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_component(self, obj): - if obj.component is None: - return None - serializer = get_serializer_for_model(obj.component) - context = {'request': self.context['request']} - return serializer(obj.component, nested=True, context=context).data diff --git a/netbox/dcim/api/serializers_/devices.py b/netbox/dcim/api/serializers_/devices.py index 2a3e0cd42..c8de28fd8 100644 --- a/netbox/dcim/api/serializers_/devices.py +++ b/netbox/dcim/api/serializers_/devices.py @@ -11,9 +11,9 @@ from dcim.models import Device, DeviceBay, MACAddress, Module, VirtualDeviceCont from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from ipam.api.serializers_.ip import IPAddressSerializer from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer -from utilities.api import get_serializer_for_model from virtualization.api.serializers_.clusters import ClusterSerializer from .devicetypes import * from .nested import NestedDeviceBaySerializer, NestedDeviceSerializer, NestedModuleBaySerializer @@ -165,7 +165,7 @@ class MACAddressSerializer(PrimaryModelSerializer): required=False, allow_null=True ) - assigned_object = serializers.SerializerMethodField(read_only=True) + assigned_object = GFKSerializerField(read_only=True) class Meta: model = MACAddress @@ -174,11 +174,3 @@ class MACAddressSerializer(PrimaryModelSerializer): 'assigned_object', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'mac_address', 'description') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_assigned_object(self, obj): - if obj.assigned_object is None: - return None - serializer = get_serializer_for_model(obj.assigned_object) - context = {'request': self.context['request']} - return serializer(obj.assigned_object, nested=True, context=context).data diff --git a/netbox/dcim/api/serializers_/devicetype_components.py b/netbox/dcim/api/serializers_/devicetype_components.py index 5f2d4b36a..b44565d65 100644 --- a/netbox/dcim/api/serializers_/devicetype_components.py +++ b/netbox/dcim/api/serializers_/devicetype_components.py @@ -1,5 +1,4 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from dcim.choices import * @@ -9,8 +8,8 @@ from dcim.models import ( InventoryItemTemplate, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate, RearPortTemplate, ) from netbox.api.fields import ChoiceField, ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer -from utilities.api import get_serializer_for_model from wireless.choices import * from .devicetypes import DeviceTypeSerializer, ModuleTypeSerializer from .manufacturers import ManufacturerSerializer @@ -313,7 +312,7 @@ class InventoryItemTemplateSerializer(ComponentTemplateSerializer): required=False, allow_null=True ) - component = serializers.SerializerMethodField(read_only=True, allow_null=True) + component = GFKSerializerField(read_only=True) _depth = serializers.IntegerField(source='level', read_only=True) class Meta: @@ -324,11 +323,3 @@ class InventoryItemTemplateSerializer(ComponentTemplateSerializer): '_depth', ] brief_fields = ('id', 'url', 'display', 'name', 'description', '_depth') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_component(self, obj): - if obj.component is None: - return None - serializer = get_serializer_for_model(obj.component) - context = {'request': self.context['request']} - return serializer(obj.component, nested=True, context=context).data diff --git a/netbox/extras/api/serializers_/attachments.py b/netbox/extras/api/serializers_/attachments.py index 6507a12be..613825203 100644 --- a/netbox/extras/api/serializers_/attachments.py +++ b/netbox/extras/api/serializers_/attachments.py @@ -1,12 +1,11 @@ from django.core.exceptions import ObjectDoesNotExist -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from core.models import ObjectType from extras.models import ImageAttachment from netbox.api.fields import ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ValidatedModelSerializer -from utilities.api import get_serializer_for_model __all__ = ( 'ImageAttachmentSerializer', @@ -17,7 +16,7 @@ class ImageAttachmentSerializer(ValidatedModelSerializer): object_type = ContentTypeField( queryset=ObjectType.objects.all() ) - parent = serializers.SerializerMethodField(read_only=True) + parent = GFKSerializerField(read_only=True) image_width = serializers.IntegerField(read_only=True) image_height = serializers.IntegerField(read_only=True) @@ -43,9 +42,3 @@ class ImageAttachmentSerializer(ValidatedModelSerializer): super().validate(data) return data - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_parent(self, obj): - serializer = get_serializer_for_model(obj.parent) - context = {'request': self.context['request']} - return serializer(obj.parent, nested=True, context=context).data diff --git a/netbox/extras/api/serializers_/bookmarks.py b/netbox/extras/api/serializers_/bookmarks.py index a404d83c3..a1c56f5f0 100644 --- a/netbox/extras/api/serializers_/bookmarks.py +++ b/netbox/extras/api/serializers_/bookmarks.py @@ -1,12 +1,9 @@ -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers - from core.models import ObjectType from extras.models import Bookmark from netbox.api.fields import ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ValidatedModelSerializer from users.api.serializers_.users import UserSerializer -from utilities.api import get_serializer_for_model __all__ = ( 'BookmarkSerializer', @@ -17,7 +14,7 @@ class BookmarkSerializer(ValidatedModelSerializer): object_type = ContentTypeField( queryset=ObjectType.objects.with_feature('bookmarks'), ) - object = serializers.SerializerMethodField(read_only=True) + object = GFKSerializerField(read_only=True) user = UserSerializer(nested=True) class Meta: @@ -26,9 +23,3 @@ class BookmarkSerializer(ValidatedModelSerializer): 'id', 'url', 'display', 'object_type', 'object_id', 'object', 'user', 'created', ] brief_fields = ('id', 'url', 'display', 'object_id', 'object_type') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_object(self, instance): - serializer = get_serializer_for_model(instance.object) - context = {'request': self.context['request']} - return serializer(instance.object, nested=True, context=context).data diff --git a/netbox/extras/api/serializers_/journaling.py b/netbox/extras/api/serializers_/journaling.py index cba56fc32..03ec34451 100644 --- a/netbox/extras/api/serializers_/journaling.py +++ b/netbox/extras/api/serializers_/journaling.py @@ -1,14 +1,13 @@ from django.core.exceptions import ObjectDoesNotExist -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from core.models import ObjectType from extras.choices import * from extras.models import JournalEntry from netbox.api.fields import ChoiceField, ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NetBoxModelSerializer from users.models import User -from utilities.api import get_serializer_for_model __all__ = ( 'JournalEntrySerializer', @@ -19,7 +18,7 @@ class JournalEntrySerializer(NetBoxModelSerializer): assigned_object_type = ContentTypeField( queryset=ObjectType.objects.all() ) - assigned_object = serializers.SerializerMethodField(read_only=True) + assigned_object = GFKSerializerField(read_only=True) created_by = serializers.PrimaryKeyRelatedField( allow_null=True, queryset=User.objects.all(), @@ -51,9 +50,3 @@ class JournalEntrySerializer(NetBoxModelSerializer): ) return super().validate(data) - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_assigned_object(self, instance): - serializer = get_serializer_for_model(instance.assigned_object_type.model_class()) - context = {'request': self.context['request']} - return serializer(instance.assigned_object, nested=True, context=context).data diff --git a/netbox/extras/api/serializers_/notifications.py b/netbox/extras/api/serializers_/notifications.py index 9f0c7cff3..4c9d08169 100644 --- a/netbox/extras/api/serializers_/notifications.py +++ b/netbox/extras/api/serializers_/notifications.py @@ -1,13 +1,10 @@ -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers - from core.models import ObjectType from extras.models import Notification, NotificationGroup, Subscription from netbox.api.fields import ContentTypeField, SerializedPKRelatedField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from users.api.serializers_.users import GroupSerializer, UserSerializer from users.models import Group, User -from utilities.api import get_serializer_for_model __all__ = ( 'NotificationSerializer', @@ -20,7 +17,7 @@ class NotificationSerializer(ValidatedModelSerializer): object_type = ContentTypeField( queryset=ObjectType.objects.with_feature('notifications'), ) - object = serializers.SerializerMethodField(read_only=True) + object = GFKSerializerField(read_only=True) user = UserSerializer(nested=True) class Meta: @@ -30,12 +27,6 @@ class NotificationSerializer(ValidatedModelSerializer): ] brief_fields = ('id', 'url', 'display', 'object_type', 'object_id', 'user', 'read', 'event_type') - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_object(self, instance): - serializer = get_serializer_for_model(instance.object) - context = {'request': self.context['request']} - return serializer(instance.object, nested=True, context=context).data - class NotificationGroupSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): groups = SerializedPKRelatedField( @@ -65,7 +56,7 @@ class SubscriptionSerializer(ValidatedModelSerializer): object_type = ContentTypeField( queryset=ObjectType.objects.with_feature('notifications'), ) - object = serializers.SerializerMethodField(read_only=True) + object = GFKSerializerField(read_only=True) user = UserSerializer(nested=True) class Meta: @@ -74,9 +65,3 @@ class SubscriptionSerializer(ValidatedModelSerializer): 'id', 'url', 'display', 'object_type', 'object_id', 'object', 'user', 'created', ] brief_fields = ('id', 'url', 'display', 'object_type', 'object_id', 'user') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_object(self, instance): - serializer = get_serializer_for_model(instance.object) - context = {'request': self.context['request']} - return serializer(instance.object, nested=True, context=context).data diff --git a/netbox/ipam/api/serializers_/fhrpgroups.py b/netbox/ipam/api/serializers_/fhrpgroups.py index 82750f1ba..cf8770682 100644 --- a/netbox/ipam/api/serializers_/fhrpgroups.py +++ b/netbox/ipam/api/serializers_/fhrpgroups.py @@ -1,11 +1,8 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers - from ipam.models import FHRPGroup, FHRPGroupAssignment from netbox.api.fields import ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NetBoxModelSerializer, PrimaryModelSerializer -from utilities.api import get_serializer_for_model from .ip import IPAddressSerializer __all__ = ( @@ -31,7 +28,7 @@ class FHRPGroupAssignmentSerializer(NetBoxModelSerializer): interface_type = ContentTypeField( queryset=ContentType.objects.all() ) - interface = serializers.SerializerMethodField(read_only=True) + interface = GFKSerializerField(read_only=True) class Meta: model = FHRPGroupAssignment @@ -40,11 +37,3 @@ class FHRPGroupAssignmentSerializer(NetBoxModelSerializer): 'priority', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'priority') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_interface(self, obj): - if obj.interface is None: - return None - serializer = get_serializer_for_model(obj.interface) - context = {'request': self.context['request']} - return serializer(obj.interface, nested=True, context=context).data diff --git a/netbox/ipam/api/serializers_/ip.py b/netbox/ipam/api/serializers_/ip.py index 7dd277479..51f23f88d 100644 --- a/netbox/ipam/api/serializers_/ip.py +++ b/netbox/ipam/api/serializers_/ip.py @@ -1,5 +1,4 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from dcim.constants import LOCATION_SCOPE_TYPES @@ -7,9 +6,9 @@ from ipam.choices import * from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS from ipam.models import Aggregate, IPAddress, IPRange, Prefix from netbox.api.fields import ChoiceField, ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import PrimaryModelSerializer 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 @@ -55,7 +54,7 @@ class PrefixSerializer(PrimaryModelSerializer): default=None ) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) - scope = serializers.SerializerMethodField(read_only=True) + scope = GFKSerializerField(read_only=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True) vlan = VLANSerializer(nested=True, required=False, allow_null=True) status = ChoiceField(choices=PrefixStatusChoices, required=False) @@ -73,14 +72,6 @@ class PrefixSerializer(PrimaryModelSerializer): ] brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth') - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_scope(self, obj): - if obj.scope_id is None: - return None - serializer = get_serializer_for_model(obj.scope) - context = {'request': self.context['request']} - return serializer(obj.scope, nested=True, context=context).data - class PrefixLengthSerializer(serializers.Serializer): @@ -168,7 +159,7 @@ class IPAddressSerializer(PrimaryModelSerializer): required=False, allow_null=True ) - assigned_object = serializers.SerializerMethodField(read_only=True) + assigned_object = GFKSerializerField(read_only=True) nat_inside = NestedIPAddressSerializer(required=False, allow_null=True) nat_outside = NestedIPAddressSerializer(many=True, read_only=True) @@ -181,14 +172,6 @@ class IPAddressSerializer(PrimaryModelSerializer): ] brief_fields = ('id', 'url', 'display', 'family', 'address', 'description') - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_assigned_object(self, obj): - if obj.assigned_object is None: - return None - serializer = get_serializer_for_model(obj.assigned_object) - context = {'request': self.context['request']} - return serializer(obj.assigned_object, nested=True, context=context).data - class AvailableIPSerializer(serializers.Serializer): """ diff --git a/netbox/ipam/api/serializers_/services.py b/netbox/ipam/api/serializers_/services.py index ad7c3e00b..824fc5738 100644 --- a/netbox/ipam/api/serializers_/services.py +++ b/netbox/ipam/api/serializers_/services.py @@ -1,13 +1,11 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers from ipam.choices import * from ipam.constants import SERVICE_ASSIGNMENT_MODELS from ipam.models import IPAddress, Service, ServiceTemplate from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import PrimaryModelSerializer -from utilities.api import get_serializer_for_model from .ip import IPAddressSerializer __all__ = ( @@ -40,7 +38,7 @@ class ServiceSerializer(PrimaryModelSerializer): parent_object_type = ContentTypeField( queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS) ) - parent = serializers.SerializerMethodField(read_only=True) + parent = GFKSerializerField(read_only=True) class Meta: model = Service @@ -50,11 +48,3 @@ class ServiceSerializer(PrimaryModelSerializer): 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_parent(self, obj): - if obj.parent is None: - return None - serializer = get_serializer_for_model(obj.parent) - context = {'request': self.context['request']} - return serializer(obj.parent, nested=True, context=context).data diff --git a/netbox/ipam/api/serializers_/vlans.py b/netbox/ipam/api/serializers_/vlans.py index 7f2633e27..133adb12c 100644 --- a/netbox/ipam/api/serializers_/vlans.py +++ b/netbox/ipam/api/serializers_/vlans.py @@ -1,5 +1,4 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from dcim.api.serializers_.sites import SiteSerializer @@ -7,9 +6,9 @@ from ipam.choices import * from ipam.constants import VLANGROUP_SCOPE_TYPES from ipam.models import VLAN, VLANGroup, VLANTranslationPolicy, VLANTranslationRule from netbox.api.fields import ChoiceField, ContentTypeField, IntegerRangeSerializer, RelatedObjectCountField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer -from utilities.api import get_serializer_for_model from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer from .nested import NestedVLANSerializer from .roles import RoleSerializer @@ -34,7 +33,7 @@ class VLANGroupSerializer(OrganizationalModelSerializer): default=None ) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) - scope = serializers.SerializerMethodField(read_only=True) + scope = GFKSerializerField(read_only=True) vid_ranges = IntegerRangeSerializer(many=True, required=False) utilization = serializers.CharField(read_only=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True) @@ -52,14 +51,6 @@ class VLANGroupSerializer(OrganizationalModelSerializer): brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count') validators = [] - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_scope(self, obj): - if obj.scope_id is None: - return None - serializer = get_serializer_for_model(obj.scope) - context = {'request': self.context['request']} - return serializer(obj.scope, nested=True, context=context).data - class VLANSerializer(PrimaryModelSerializer): site = SiteSerializer(nested=True, required=False, allow_null=True) diff --git a/netbox/netbox/api/fields2.py b/netbox/netbox/api/gfk_fields.py similarity index 100% rename from netbox/netbox/api/fields2.py rename to netbox/netbox/api/gfk_fields.py diff --git a/netbox/tenancy/api/serializers_/contacts.py b/netbox/tenancy/api/serializers_/contacts.py index 19c496139..718af4768 100644 --- a/netbox/tenancy/api/serializers_/contacts.py +++ b/netbox/tenancy/api/serializers_/contacts.py @@ -1,15 +1,13 @@ from django.contrib.auth.models import ContentType -from drf_spectacular.types import OpenApiTypes -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import ( NestedGroupModelSerializer, NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer, ) from tenancy.choices import ContactPriorityChoices from tenancy.models import ContactAssignment, Contact, ContactGroup, ContactRole -from utilities.api import get_serializer_for_model from .nested import NestedContactGroupSerializer __all__ = ( @@ -66,7 +64,7 @@ class ContactAssignmentSerializer(NetBoxModelSerializer): object_type = ContentTypeField( queryset=ContentType.objects.all() ) - object = serializers.SerializerMethodField(read_only=True) + object = GFKSerializerField(read_only=True) contact = ContactSerializer(nested=True) role = ContactRoleSerializer(nested=True, required=False, allow_null=True) priority = ChoiceField(choices=ContactPriorityChoices, allow_blank=True, required=False, default=lambda: '') @@ -78,9 +76,3 @@ class ContactAssignmentSerializer(NetBoxModelSerializer): 'tags', 'custom_fields', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'contact', 'role', 'priority') - - @extend_schema_field(OpenApiTypes.OBJECT) - def get_object(self, instance): - serializer = get_serializer_for_model(instance.object_type.model_class()) - context = {'request': self.context['request']} - return serializer(instance.object, nested=True, context=context).data diff --git a/netbox/virtualization/api/serializers_/clusters.py b/netbox/virtualization/api/serializers_/clusters.py index a48af9ce0..e352460bf 100644 --- a/netbox/virtualization/api/serializers_/clusters.py +++ b/netbox/virtualization/api/serializers_/clusters.py @@ -1,13 +1,12 @@ from dcim.constants import LOCATION_SCOPE_TYPES from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import OrganizationalModelSerializer, PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer from virtualization.choices import * from virtualization.models import Cluster, ClusterGroup, ClusterType -from utilities.api import get_serializer_for_model __all__ = ( 'ClusterGroupSerializer', @@ -58,7 +57,7 @@ class ClusterSerializer(PrimaryModelSerializer): default=None ) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) - scope = serializers.SerializerMethodField(read_only=True) + scope = GFKSerializerField(read_only=True) allocated_vcpus = serializers.DecimalField( read_only=True, max_digits=8, @@ -80,11 +79,3 @@ class ClusterSerializer(PrimaryModelSerializer): 'device_count', 'virtualmachine_count', 'allocated_vcpus', 'allocated_memory', 'allocated_disk' ] brief_fields = ('id', 'url', 'display', 'name', 'description', 'virtualmachine_count') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_scope(self, obj): - if obj.scope_id is None: - return None - serializer = get_serializer_for_model(obj.scope) - context = {'request': self.context['request']} - return serializer(obj.scope, nested=True, context=context).data diff --git a/netbox/vpn/api/serializers_/l2vpn.py b/netbox/vpn/api/serializers_/l2vpn.py index f9e9a9a97..874ae342e 100644 --- a/netbox/vpn/api/serializers_/l2vpn.py +++ b/netbox/vpn/api/serializers_/l2vpn.py @@ -1,13 +1,11 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers from ipam.api.serializers_.vrfs import RouteTargetSerializer from ipam.models import RouteTarget from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NetBoxModelSerializer, PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer -from utilities.api import get_serializer_for_model from vpn.choices import * from vpn.models import L2VPN, L2VPNTermination @@ -53,7 +51,7 @@ class L2VPNTerminationSerializer(NetBoxModelSerializer): assigned_object_type = ContentTypeField( queryset=ContentType.objects.all() ) - assigned_object = serializers.SerializerMethodField(read_only=True) + assigned_object = GFKSerializerField(read_only=True) class Meta: model = L2VPNTermination @@ -62,9 +60,3 @@ class L2VPNTerminationSerializer(NetBoxModelSerializer): 'assigned_object', 'tags', 'custom_fields', 'created', 'last_updated' ] brief_fields = ('id', 'url', 'display', 'l2vpn') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_assigned_object(self, instance): - serializer = get_serializer_for_model(instance.assigned_object) - context = {'request': self.context['request']} - return serializer(instance.assigned_object, nested=True, context=context).data diff --git a/netbox/vpn/api/serializers_/tunnels.py b/netbox/vpn/api/serializers_/tunnels.py index dfeb0339f..5bb12d9b4 100644 --- a/netbox/vpn/api/serializers_/tunnels.py +++ b/netbox/vpn/api/serializers_/tunnels.py @@ -1,12 +1,10 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field -from rest_framework import serializers from ipam.api.serializers_.ip import IPAddressSerializer from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer -from utilities.api import get_serializer_for_model from vpn.choices import * from vpn.models import Tunnel, TunnelGroup, TunnelTermination from .crypto import IPSecProfileSerializer @@ -83,9 +81,7 @@ class TunnelTerminationSerializer(NetBoxModelSerializer): termination_type = ContentTypeField( queryset=ContentType.objects.all() ) - termination = serializers.SerializerMethodField( - read_only=True - ) + termination = GFKSerializerField(read_only=True) outside_ip = IPAddressSerializer( nested=True, required=False, @@ -99,11 +95,3 @@ class TunnelTerminationSerializer(NetBoxModelSerializer): 'termination', 'outside_ip', 'tags', 'custom_fields', 'created', 'last_updated', ) brief_fields = ('id', 'url', 'display') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_termination(self, obj): - if not obj.termination: - return None - serializer = get_serializer_for_model(obj.termination) - context = {'request': self.context['request']} - return serializer(obj.termination, nested=True, context=context).data diff --git a/netbox/wireless/api/serializers_/wirelesslans.py b/netbox/wireless/api/serializers_/wirelesslans.py index 7403fe860..517e93863 100644 --- a/netbox/wireless/api/serializers_/wirelesslans.py +++ b/netbox/wireless/api/serializers_/wirelesslans.py @@ -1,13 +1,12 @@ from django.contrib.contenttypes.models import ContentType -from drf_spectacular.utils import extend_schema_field from rest_framework import serializers from dcim.constants import LOCATION_SCOPE_TYPES from ipam.api.serializers_.vlans import VLANSerializer from netbox.api.fields import ChoiceField, ContentTypeField +from netbox.api.gfk_fields import GFKSerializerField from netbox.api.serializers import NestedGroupModelSerializer, PrimaryModelSerializer from tenancy.api.serializers_.tenants import TenantSerializer -from utilities.api import get_serializer_for_model from wireless.choices import * from wireless.models import WirelessLAN, WirelessLANGroup from .nested import NestedWirelessLANGroupSerializer @@ -47,7 +46,7 @@ class WirelessLANSerializer(PrimaryModelSerializer): default=None ) scope_id = serializers.IntegerField(allow_null=True, required=False, default=None) - scope = serializers.SerializerMethodField(read_only=True) + scope = GFKSerializerField(read_only=True) class Meta: model = WirelessLAN @@ -57,11 +56,3 @@ class WirelessLANSerializer(PrimaryModelSerializer): 'tags', 'custom_fields', 'created', 'last_updated', ] brief_fields = ('id', 'url', 'display', 'ssid', 'description') - - @extend_schema_field(serializers.JSONField(allow_null=True)) - def get_scope(self, obj): - if obj.scope_id is None: - return None - serializer = get_serializer_for_model(obj.scope) - context = {'request': self.context['request']} - return serializer(obj.scope, nested=True, context=context).data