Closes: #17936 - GFK serializer field (#20706)
Some checks failed
CI / build (20.x, 3.12) (push) Has been cancelled
CI / build (20.x, 3.13) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled

* Establish GFKSerializerField and replace get_* methods in circuits.py

* Set read_only=True

* Apply GFKSerializerField to all matching SerializerMethodFields

* Use GFKSerializerField for ObjectChangeSerializer.changed_object and EventRuleSerializer.action_object
This commit is contained in:
bctiemann
2025-11-04 10:01:22 -05:00
committed by GitHub
parent 068d493cc6
commit bcffc383bf
22 changed files with 119 additions and 318 deletions

View File

@@ -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",
@@ -211972,8 +211972,8 @@
"nullable": true
},
"termination": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"port_speed": {
"type": "integer",
@@ -212176,8 +212176,8 @@
"format": "int64"
},
"member": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"priority": {
"type": "object",
@@ -212561,8 +212561,8 @@
"nullable": true
},
"termination": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"port_speed": {
"type": "integer",
@@ -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"
@@ -219029,9 +219028,8 @@
"nullable": true
},
"action_object": {
"type": "object",
"additionalProperties": {},
"readOnly": true
"readOnly": true,
"nullable": true
},
"description": {
"type": "string",
@@ -219536,8 +219534,8 @@
"format": "int64"
},
"interface": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"priority": {
"type": "integer",
@@ -221339,8 +221337,8 @@
"nullable": true
},
"assigned_object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"nat_inside": {
"allOf": [
@@ -222501,8 +222499,8 @@
"format": "int64"
},
"parent": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"name": {
"type": "string",
@@ -225660,8 +225658,8 @@
"nullable": true
},
"component": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"tags": {
"type": "array",
@@ -226044,8 +226042,8 @@
"nullable": true
},
"component": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"created": {
"type": "string",
@@ -226327,8 +226325,8 @@
"format": "int64"
},
"assigned_object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"created": {
"type": "string",
@@ -226777,8 +226775,8 @@
"format": "int64"
},
"assigned_object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"tags": {
"type": "array",
@@ -227155,8 +227153,8 @@
"nullable": true
},
"assigned_object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"description": {
"type": "string",
@@ -229542,8 +229540,8 @@
"format": "int64"
},
"object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"user": {
"$ref": "#/components/schemas/BriefUser"
@@ -229796,7 +229794,11 @@
"format": "int64"
},
"changed_object": {
"nullable": true,
"readOnly": true,
"nullable": true
},
"object_repr": {
"type": "string",
"readOnly": true
},
"message": {
@@ -229821,6 +229823,7 @@
"display_url",
"id",
"message",
"object_repr",
"postchange_data",
"prechange_data",
"request_id",
@@ -248892,8 +248895,8 @@
"nullable": true
},
"scope": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"tenant": {
"allOf": [
@@ -252745,8 +252748,8 @@
"format": "int64"
},
"parent": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"name": {
"type": "string",
@@ -253669,8 +253672,8 @@
"format": "int64"
},
"object": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"user": {
"$ref": "#/components/schemas/BriefUser"
@@ -255193,8 +255196,8 @@
"nullable": true
},
"termination": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"outside_ip": {
"allOf": [
@@ -255671,8 +255674,8 @@
"nullable": true
},
"scope": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"vid_ranges": {
"type": "array",
@@ -258528,8 +258531,8 @@
"nullable": true
},
"scope": {
"nullable": true,
"readOnly": true
"readOnly": true,
"nullable": true
},
"tenant": {
"allOf": [

View File

@@ -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 circuits.choices import CircuitPriorityChoices, CircuitStatusChoices, VirtualCircuitTerminationRoleChoices
@@ -11,12 +10,12 @@ 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.gfk_fields import GFKSerializerField
from netbox.api.serializers import (
NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer, WritableNestedSerializer,
)
from netbox.choices import DistanceUnitChoices
from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model
from .providers import ProviderAccountSerializer, ProviderNetworkSerializer, ProviderSerializer
__all__ = (
@@ -55,7 +54,7 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
default=None
)
termination_id = serializers.IntegerField(allow_null=True, required=False, default=None)
termination = serializers.SerializerMethodField(read_only=True)
termination = GFKSerializerField(read_only=True)
class Meta:
model = CircuitTermination
@@ -64,14 +63,6 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
'upstream_speed', 'xconnect_id', 'description',
]
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_termination(self, obj):
if obj.termination_id is None:
return None
serializer = get_serializer_for_model(obj.termination)
context = {'request': self.context['request']}
return serializer(obj.termination, nested=True, context=context).data
class CircuitGroupSerializer(OrganizationalModelSerializer):
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -134,7 +125,7 @@ class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer
default=None
)
termination_id = serializers.IntegerField(allow_null=True, required=False, default=None)
termination = serializers.SerializerMethodField(read_only=True)
termination = GFKSerializerField(read_only=True)
class Meta:
model = CircuitTermination
@@ -146,20 +137,12 @@ class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer
]
brief_fields = ('id', 'url', 'display', 'circuit', 'term_side', 'description', 'cable', '_occupied')
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_termination(self, obj):
if obj.termination_id is None:
return None
serializer = get_serializer_for_model(obj.termination)
context = {'request': self.context['request']}
return serializer(obj.termination, nested=True, context=context).data
class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_):
member_type = ContentTypeField(
queryset=ContentType.objects.filter(CIRCUIT_GROUP_ASSIGNMENT_MEMBER_MODELS)
)
member = serializers.SerializerMethodField(read_only=True)
member = GFKSerializerField(read_only=True)
class Meta:
model = CircuitGroupAssignment
@@ -169,14 +152,6 @@ class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_):
]
brief_fields = ('id', 'url', 'display', 'group', 'member_type', 'member_id', 'member', 'priority')
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_member(self, obj):
if obj.member_id is None:
return None
serializer = get_serializer_for_model(obj.member)
context = {'request': self.context['request']}
return serializer(obj.member, nested=True, context=context).data
class VirtualCircuitTypeSerializer(OrganizationalModelSerializer):

View File

@@ -1,13 +1,11 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from core.choices import *
from core.models import ObjectChange
from netbox.api.exceptions import SerializerNotFound
from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.gfk_fields import GFKSerializerField
from netbox.api.serializers import BaseModelSerializer
from users.api.serializers_.users import UserSerializer
from utilities.api import get_serializer_for_model
__all__ = (
'ObjectChangeSerializer',
@@ -26,7 +24,10 @@ class ObjectChangeSerializer(BaseModelSerializer):
changed_object_type = ContentTypeField(
read_only=True
)
changed_object = serializers.SerializerMethodField(
changed_object = GFKSerializerField(
read_only=True
)
object_repr = serializers.CharField(
read_only=True
)
prechange_data = serializers.JSONField(
@@ -44,22 +45,6 @@ class ObjectChangeSerializer(BaseModelSerializer):
model = ObjectChange
fields = [
'id', 'url', 'display_url', 'display', 'time', 'user', 'user_name', 'request_id', 'action',
'changed_object_type', 'changed_object_id', 'changed_object', 'message', 'prechange_data',
'postchange_data',
'changed_object_type', 'changed_object_id', 'changed_object', 'object_repr', 'message',
'prechange_data', 'postchange_data',
]
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_changed_object(self, obj):
"""
Serialize a nested representation of the changed object.
"""
if obj.changed_object is None:
return None
try:
serializer = get_serializer_for_model(obj.changed_object)
except SerializerNotFound:
return obj.object_repr
data = serializer(obj.changed_object, nested=True, context={'request': self.context['request']}).data
return data

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,15 +1,10 @@
from drf_spectacular.types import OpenApiTypes
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 EventRule, Webhook
from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.gfk_fields import GFKSerializerField
from netbox.api.serializers import NetBoxModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from utilities.api import get_serializer_for_model
from .scripts import ScriptSerializer
__all__ = (
'EventRuleSerializer',
@@ -30,7 +25,7 @@ class EventRuleSerializer(OwnerMixin, NetBoxModelSerializer):
action_object_type = ContentTypeField(
queryset=ObjectType.objects.with_feature('event_rules'),
)
action_object = serializers.SerializerMethodField(read_only=True)
action_object = GFKSerializerField(read_only=True)
class Meta:
model = EventRule
@@ -41,17 +36,6 @@ class EventRuleSerializer(OwnerMixin, NetBoxModelSerializer):
]
brief_fields = ('id', 'url', 'display', 'name', 'description')
@extend_schema_field(OpenApiTypes.OBJECT)
def get_action_object(self, instance):
context = {'request': self.context['request']}
# We need to manually instantiate the serializer for scripts
if instance.action_type == EventRuleActionChoices.SCRIPT:
script = instance.action_object
return ScriptSerializer(script, nested=True, context=context).data
else:
serializer = get_serializer_for_model(instance.action_object_type.model_class())
return serializer(instance.action_object, nested=True, context=context).data
#
# Webhooks

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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):
"""

View File

@@ -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

View File

@@ -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)

View File

@@ -0,0 +1,18 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from utilities.api import get_serializer_for_model
__all__ = (
'GFKSerializerField',
)
@extend_schema_field(serializers.JSONField(allow_null=True, read_only=True))
class GFKSerializerField(serializers.Field):
def to_representation(self, instance, **kwargs):
if instance is None:
return None
serializer = get_serializer_for_model(instance)
context = {'request': self.context['request']}
return serializer(instance, nested=True, context=context).data

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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