mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Replace nested serializers with primary serializers where possible
This commit is contained in:
@ -2,13 +2,12 @@ from rest_framework import serializers
|
|||||||
|
|
||||||
from circuits.choices import CircuitStatusChoices
|
from circuits.choices import CircuitStatusChoices
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
from dcim.api.nested_serializers import NestedSiteSerializer
|
from dcim.api.serializers import CabledObjectSerializer, SiteSerializer
|
||||||
from dcim.api.serializers import CabledObjectSerializer
|
|
||||||
from ipam.api.nested_serializers import NestedASNSerializer
|
from ipam.api.nested_serializers import NestedASNSerializer
|
||||||
from ipam.models import ASN
|
from ipam.models import ASN
|
||||||
from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
|
from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
|
||||||
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
|
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.serializers import TenantSerializer
|
||||||
from .nested_serializers import *
|
from .nested_serializers import *
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ class ProviderSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ProviderAccountSerializer(NetBoxModelSerializer):
|
class ProviderAccountSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provideraccount-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provideraccount-detail')
|
||||||
provider = NestedProviderSerializer()
|
provider = ProviderSerializer(nested=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProviderAccount
|
model = ProviderAccount
|
||||||
@ -66,7 +65,7 @@ class ProviderAccountSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ProviderNetworkSerializer(NetBoxModelSerializer):
|
class ProviderNetworkSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
|
||||||
provider = NestedProviderSerializer()
|
provider = ProviderSerializer(nested=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProviderNetwork
|
model = ProviderNetwork
|
||||||
@ -98,8 +97,8 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
|
class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
|
||||||
site = NestedSiteSerializer(allow_null=True)
|
site = SiteSerializer(nested=True, allow_null=True)
|
||||||
provider_network = NestedProviderNetworkSerializer(allow_null=True)
|
provider_network = ProviderNetworkSerializer(nested=True, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
@ -111,11 +110,11 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
|
|||||||
|
|
||||||
class CircuitSerializer(NetBoxModelSerializer):
|
class CircuitSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
|
||||||
provider = NestedProviderSerializer()
|
provider = ProviderSerializer(nested=True)
|
||||||
provider_account = NestedProviderAccountSerializer(required=False, allow_null=True)
|
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=CircuitStatusChoices, required=False)
|
status = ChoiceField(choices=CircuitStatusChoices, required=False)
|
||||||
type = NestedCircuitTypeSerializer()
|
type = CircuitTypeSerializer(nested=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
termination_a = CircuitCircuitTerminationSerializer(read_only=True, allow_null=True)
|
termination_a = CircuitCircuitTerminationSerializer(read_only=True, allow_null=True)
|
||||||
termination_z = CircuitCircuitTerminationSerializer(read_only=True, allow_null=True)
|
termination_z = CircuitCircuitTerminationSerializer(read_only=True, allow_null=True)
|
||||||
|
|
||||||
@ -131,9 +130,9 @@ class CircuitSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer):
|
class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
|
||||||
circuit = NestedCircuitSerializer()
|
circuit = CircuitSerializer(nested=True)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = SiteSerializer(nested=True, required=False, allow_null=True)
|
||||||
provider_network = NestedProviderNetworkSerializer(required=False, allow_null=True)
|
provider_network = ProviderNetworkSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
|
@ -4,7 +4,7 @@ from core.choices import JobStatusChoices
|
|||||||
from core.models import *
|
from core.models import *
|
||||||
from netbox.api.fields import ChoiceField
|
from netbox.api.fields import ChoiceField
|
||||||
from netbox.api.serializers import WritableNestedSerializer
|
from netbox.api.serializers import WritableNestedSerializer
|
||||||
from users.api.nested_serializers import NestedUserSerializer
|
from users.api.serializers import UserSerializer
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'NestedDataFileSerializer',
|
'NestedDataFileSerializer',
|
||||||
@ -32,7 +32,8 @@ class NestedDataFileSerializer(WritableNestedSerializer):
|
|||||||
class NestedJobSerializer(serializers.ModelSerializer):
|
class NestedJobSerializer(serializers.ModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
|
||||||
status = ChoiceField(choices=JobStatusChoices)
|
status = ChoiceField(choices=JobStatusChoices)
|
||||||
user = NestedUserSerializer(
|
user = UserSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,8 +5,7 @@ from core.models import *
|
|||||||
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
|
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
|
||||||
from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer
|
from netbox.api.serializers import BaseModelSerializer, NetBoxModelSerializer
|
||||||
from netbox.utils import get_data_backend_choices
|
from netbox.utils import get_data_backend_choices
|
||||||
from users.api.nested_serializers import NestedUserSerializer
|
from users.api.serializers import UserSerializer
|
||||||
from .nested_serializers import *
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'DataFileSerializer',
|
'DataFileSerializer',
|
||||||
@ -43,7 +42,8 @@ class DataFileSerializer(NetBoxModelSerializer):
|
|||||||
url = serializers.HyperlinkedIdentityField(
|
url = serializers.HyperlinkedIdentityField(
|
||||||
view_name='core-api:datafile-detail'
|
view_name='core-api:datafile-detail'
|
||||||
)
|
)
|
||||||
source = NestedDataSourceSerializer(
|
source = DataSourceSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,7 +57,8 @@ class DataFileSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class JobSerializer(BaseModelSerializer):
|
class JobSerializer(BaseModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
|
||||||
user = NestedUserSerializer(
|
user = UserSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
status = ChoiceField(choices=JobStatusChoices, read_only=True)
|
status = ChoiceField(choices=JobStatusChoices, read_only=True)
|
||||||
|
@ -6,8 +6,6 @@ from netbox.api.fields import RelatedObjectCountField
|
|||||||
from netbox.api.serializers import WritableNestedSerializer
|
from netbox.api.serializers import WritableNestedSerializer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ComponentNestedModuleSerializer',
|
|
||||||
'ModuleBayNestedModuleSerializer',
|
|
||||||
'NestedCableSerializer',
|
'NestedCableSerializer',
|
||||||
'NestedConsolePortSerializer',
|
'NestedConsolePortSerializer',
|
||||||
'NestedConsolePortTemplateSerializer',
|
'NestedConsolePortTemplateSerializer',
|
||||||
@ -311,26 +309,6 @@ class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
|
|||||||
fields = ['id', 'url', 'display', 'name']
|
fields = ['id', 'url', 'display', 'name']
|
||||||
|
|
||||||
|
|
||||||
class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Module
|
|
||||||
fields = ['id', 'url', 'display', 'serial']
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentNestedModuleSerializer(WritableNestedSerializer):
|
|
||||||
"""
|
|
||||||
Used by device component serializers.
|
|
||||||
"""
|
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
|
|
||||||
module_bay = ModuleNestedModuleBaySerializer(read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Module
|
|
||||||
fields = ['id', 'url', 'display', 'device', 'module_bay']
|
|
||||||
|
|
||||||
|
|
||||||
class NestedModuleSerializer(WritableNestedSerializer):
|
class NestedModuleSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
|
||||||
device = NestedDeviceSerializer(read_only=True)
|
device = NestedDeviceSerializer(read_only=True)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ from rest_framework.response import Response
|
|||||||
from rest_framework.status import HTTP_400_BAD_REQUEST
|
from rest_framework.status import HTTP_400_BAD_REQUEST
|
||||||
|
|
||||||
from netbox.api.renderers import TextRenderer
|
from netbox.api.renderers import TextRenderer
|
||||||
from .nested_serializers import NestedConfigTemplateSerializer
|
from .serializers import ConfigTemplateSerializer
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ConfigContextQuerySetMixin',
|
'ConfigContextQuerySetMixin',
|
||||||
@ -52,7 +52,7 @@ class ConfigTemplateRenderMixin:
|
|||||||
if request.accepted_renderer.format == 'txt':
|
if request.accepted_renderer.format == 'txt':
|
||||||
return Response(output)
|
return Response(output)
|
||||||
|
|
||||||
template_serializer = NestedConfigTemplateSerializer(configtemplate, context={'request': request})
|
template_serializer = ConfigTemplateSerializer(configtemplate, nested=True, context={'request': request})
|
||||||
|
|
||||||
return Response({
|
return Response({
|
||||||
'configtemplate': template_serializer.data,
|
'configtemplate': template_serializer.data,
|
||||||
|
@ -5,8 +5,7 @@ from drf_spectacular.types import OpenApiTypes
|
|||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from core.api.nested_serializers import NestedDataSourceSerializer, NestedDataFileSerializer, NestedJobSerializer
|
from core.api.serializers import DataFileSerializer, DataSourceSerializer, JobSerializer
|
||||||
from core.api.serializers import JobSerializer
|
|
||||||
from core.models import ContentType
|
from core.models import ContentType
|
||||||
from dcim.api.nested_serializers import (
|
from dcim.api.nested_serializers import (
|
||||||
NestedDeviceRoleSerializer, NestedDeviceTypeSerializer, NestedLocationSerializer, NestedPlatformSerializer,
|
NestedDeviceRoleSerializer, NestedDeviceTypeSerializer, NestedLocationSerializer, NestedPlatformSerializer,
|
||||||
@ -22,7 +21,7 @@ from netbox.api.serializers.features import TaggableModelSerializer
|
|||||||
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
|
from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
|
||||||
from tenancy.models import Tenant, TenantGroup
|
from tenancy.models import Tenant, TenantGroup
|
||||||
from users.api.nested_serializers import NestedUserSerializer
|
from users.api.serializers import UserSerializer
|
||||||
from utilities.api import get_serializer_for_model
|
from utilities.api import get_serializer_for_model
|
||||||
from virtualization.api.nested_serializers import (
|
from virtualization.api.nested_serializers import (
|
||||||
NestedClusterGroupSerializer, NestedClusterSerializer, NestedClusterTypeSerializer,
|
NestedClusterGroupSerializer, NestedClusterSerializer, NestedClusterTypeSerializer,
|
||||||
@ -115,6 +114,28 @@ class WebhookSerializer(NetBoxModelSerializer):
|
|||||||
# Custom fields
|
# Custom fields
|
||||||
#
|
#
|
||||||
|
|
||||||
|
class CustomFieldChoiceSetSerializer(ValidatedModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfieldchoiceset-detail')
|
||||||
|
base_choices = ChoiceField(
|
||||||
|
choices=CustomFieldChoiceSetBaseChoices,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
extra_choices = serializers.ListField(
|
||||||
|
child=serializers.ListField(
|
||||||
|
min_length=2,
|
||||||
|
max_length=2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CustomFieldChoiceSet
|
||||||
|
fields = [
|
||||||
|
'id', 'url', 'display', 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
|
||||||
|
'choices_count', 'created', 'last_updated',
|
||||||
|
]
|
||||||
|
brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldSerializer(ValidatedModelSerializer):
|
class CustomFieldSerializer(ValidatedModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
|
||||||
content_types = ContentTypeField(
|
content_types = ContentTypeField(
|
||||||
@ -129,7 +150,8 @@ class CustomFieldSerializer(ValidatedModelSerializer):
|
|||||||
)
|
)
|
||||||
filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
|
filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
|
||||||
data_type = serializers.SerializerMethodField()
|
data_type = serializers.SerializerMethodField()
|
||||||
choice_set = NestedCustomFieldChoiceSetSerializer(
|
choice_set = CustomFieldChoiceSetSerializer(
|
||||||
|
nested=True,
|
||||||
required=False,
|
required=False,
|
||||||
allow_null=True
|
allow_null=True
|
||||||
)
|
)
|
||||||
@ -168,28 +190,6 @@ class CustomFieldSerializer(ValidatedModelSerializer):
|
|||||||
return 'string'
|
return 'string'
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldChoiceSetSerializer(ValidatedModelSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfieldchoiceset-detail')
|
|
||||||
base_choices = ChoiceField(
|
|
||||||
choices=CustomFieldChoiceSetBaseChoices,
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
extra_choices = serializers.ListField(
|
|
||||||
child=serializers.ListField(
|
|
||||||
min_length=2,
|
|
||||||
max_length=2
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = CustomFieldChoiceSet
|
|
||||||
fields = [
|
|
||||||
'id', 'url', 'display', 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
|
|
||||||
'choices_count', 'created', 'last_updated',
|
|
||||||
]
|
|
||||||
brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Custom links
|
# Custom links
|
||||||
#
|
#
|
||||||
@ -220,10 +220,12 @@ class ExportTemplateSerializer(ValidatedModelSerializer):
|
|||||||
queryset=ContentType.objects.with_feature('export_templates'),
|
queryset=ContentType.objects.with_feature('export_templates'),
|
||||||
many=True
|
many=True
|
||||||
)
|
)
|
||||||
data_source = NestedDataSourceSerializer(
|
data_source = DataSourceSerializer(
|
||||||
|
nested=True,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
data_file = NestedDataFileSerializer(
|
data_file = DataFileSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -267,7 +269,7 @@ class BookmarkSerializer(ValidatedModelSerializer):
|
|||||||
queryset=ContentType.objects.with_feature('bookmarks'),
|
queryset=ContentType.objects.with_feature('bookmarks'),
|
||||||
)
|
)
|
||||||
object = serializers.SerializerMethodField(read_only=True)
|
object = serializers.SerializerMethodField(read_only=True)
|
||||||
user = NestedUserSerializer()
|
user = UserSerializer(nested=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Bookmark
|
model = Bookmark
|
||||||
@ -482,10 +484,12 @@ class ConfigContextSerializer(ValidatedModelSerializer):
|
|||||||
required=False,
|
required=False,
|
||||||
many=True
|
many=True
|
||||||
)
|
)
|
||||||
data_source = NestedDataSourceSerializer(
|
data_source = DataSourceSerializer(
|
||||||
|
nested=True,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
data_file = NestedDataFileSerializer(
|
data_file = DataFileSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -506,10 +510,12 @@ class ConfigContextSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
|
class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
|
||||||
data_source = NestedDataSourceSerializer(
|
data_source = DataSourceSerializer(
|
||||||
|
nested=True,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
data_file = NestedDataFileSerializer(
|
data_file = DataFileSerializer(
|
||||||
|
nested=True,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -530,7 +536,7 @@ class ScriptSerializer(ValidatedModelSerializer):
|
|||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:script-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:script-detail')
|
||||||
description = serializers.SerializerMethodField(read_only=True)
|
description = serializers.SerializerMethodField(read_only=True)
|
||||||
vars = serializers.SerializerMethodField(read_only=True)
|
vars = serializers.SerializerMethodField(read_only=True)
|
||||||
result = NestedJobSerializer(read_only=True)
|
result = JobSerializer(nested=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Script
|
model = Script
|
||||||
@ -596,7 +602,8 @@ class ScriptInputSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
class ObjectChangeSerializer(BaseModelSerializer):
|
class ObjectChangeSerializer(BaseModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:objectchange-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:objectchange-detail')
|
||||||
user = NestedUserSerializer(
|
user = UserSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
action = ChoiceField(
|
action = ChoiceField(
|
||||||
|
@ -2,29 +2,48 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerializer
|
from dcim.api.serializers import DeviceSerializer, SiteSerializer
|
||||||
from ipam.choices import *
|
from ipam.choices import *
|
||||||
from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS, VLANGROUP_SCOPE_TYPES
|
from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS, VLANGROUP_SCOPE_TYPES
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
|
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
|
||||||
from netbox.api.serializers import NetBoxModelSerializer
|
from netbox.api.serializers import NetBoxModelSerializer
|
||||||
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.serializers import TenantSerializer
|
||||||
from utilities.api import get_serializer_for_model
|
from utilities.api import get_serializer_for_model
|
||||||
from virtualization.api.nested_serializers import NestedVirtualMachineSerializer
|
from virtualization.api.serializers import VirtualMachineSerializer
|
||||||
from vpn.api.nested_serializers import NestedL2VPNTerminationSerializer
|
from vpn.api.nested_serializers import NestedL2VPNTerminationSerializer
|
||||||
from .field_serializers import IPAddressField, IPNetworkField
|
from .field_serializers import IPAddressField, IPNetworkField
|
||||||
from .nested_serializers import *
|
from .nested_serializers import *
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# RIRs
|
||||||
|
#
|
||||||
|
|
||||||
|
class RIRSerializer(NetBoxModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
|
||||||
|
|
||||||
|
# Related object counts
|
||||||
|
aggregate_count = RelatedObjectCountField('aggregates')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = RIR
|
||||||
|
fields = [
|
||||||
|
'id', 'url', 'display', 'name', 'slug', 'is_private', 'description', 'tags', 'custom_fields', 'created',
|
||||||
|
'last_updated', 'aggregate_count',
|
||||||
|
]
|
||||||
|
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ASN ranges
|
# ASN ranges
|
||||||
#
|
#
|
||||||
|
|
||||||
class ASNRangeSerializer(NetBoxModelSerializer):
|
class ASNRangeSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asnrange-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asnrange-detail')
|
||||||
rir = NestedRIRSerializer()
|
rir = RIRSerializer(nested=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
asn_count = serializers.IntegerField(read_only=True)
|
asn_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -42,8 +61,8 @@ class ASNRangeSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ASNSerializer(NetBoxModelSerializer):
|
class ASNSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
|
||||||
rir = NestedRIRSerializer(required=False, allow_null=True)
|
rir = RIRSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
# Related object counts
|
# Related object counts
|
||||||
site_count = RelatedObjectCountField('sites')
|
site_count = RelatedObjectCountField('sites')
|
||||||
@ -66,7 +85,7 @@ class AvailableASNSerializer(serializers.Serializer):
|
|||||||
description = serializers.CharField(required=False)
|
description = serializers.CharField(required=False)
|
||||||
|
|
||||||
def to_representation(self, asn):
|
def to_representation(self, asn):
|
||||||
rir = NestedRIRSerializer(self.context['range'].rir, context={
|
rir = RIRSerializer(self.context['range'].rir, nested=True, context={
|
||||||
'request': self.context['request']
|
'request': self.context['request']
|
||||||
}).data
|
}).data
|
||||||
return {
|
return {
|
||||||
@ -81,7 +100,7 @@ class AvailableASNSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
class VRFSerializer(NetBoxModelSerializer):
|
class VRFSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
import_targets = SerializedPKRelatedField(
|
import_targets = SerializedPKRelatedField(
|
||||||
queryset=RouteTarget.objects.all(),
|
queryset=RouteTarget.objects.all(),
|
||||||
serializer=NestedRouteTargetSerializer,
|
serializer=NestedRouteTargetSerializer,
|
||||||
@ -109,13 +128,9 @@ class VRFSerializer(NetBoxModelSerializer):
|
|||||||
brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count')
|
brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count')
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Route targets
|
|
||||||
#
|
|
||||||
|
|
||||||
class RouteTargetSerializer(NetBoxModelSerializer):
|
class RouteTargetSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RouteTarget
|
model = RouteTarget
|
||||||
@ -127,29 +142,14 @@ class RouteTargetSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# RIRs/aggregates
|
# Aggregates
|
||||||
#
|
#
|
||||||
|
|
||||||
class RIRSerializer(NetBoxModelSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
|
|
||||||
|
|
||||||
# Related object counts
|
|
||||||
aggregate_count = RelatedObjectCountField('aggregates')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = RIR
|
|
||||||
fields = [
|
|
||||||
'id', 'url', 'display', 'name', 'slug', 'is_private', 'description', 'tags', 'custom_fields', 'created',
|
|
||||||
'last_updated', 'aggregate_count',
|
|
||||||
]
|
|
||||||
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count')
|
|
||||||
|
|
||||||
|
|
||||||
class AggregateSerializer(NetBoxModelSerializer):
|
class AggregateSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail')
|
||||||
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
||||||
rir = NestedRIRSerializer()
|
rir = RIRSerializer(nested=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
prefix = IPNetworkField()
|
prefix = IPNetworkField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -180,7 +180,7 @@ class FHRPGroupSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
|
class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail')
|
||||||
group = NestedFHRPGroupSerializer()
|
group = FHRPGroupSerializer(nested=True)
|
||||||
interface_type = ContentTypeField(
|
interface_type = ContentTypeField(
|
||||||
queryset=ContentType.objects.all()
|
queryset=ContentType.objects.all()
|
||||||
)
|
)
|
||||||
@ -261,11 +261,11 @@ class VLANGroupSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class VLANSerializer(NetBoxModelSerializer):
|
class VLANSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = SiteSerializer(nested=True, required=False, allow_null=True)
|
||||||
group = NestedVLANGroupSerializer(required=False, allow_null=True, default=None)
|
group = VLANGroupSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=VLANStatusChoices, required=False)
|
status = ChoiceField(choices=VLANStatusChoices, required=False)
|
||||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
role = RoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True, allow_null=True)
|
l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True, allow_null=True)
|
||||||
|
|
||||||
# Related object counts
|
# Related object counts
|
||||||
@ -285,23 +285,24 @@ class AvailableVLANSerializer(serializers.Serializer):
|
|||||||
Representation of a VLAN which does not exist in the database.
|
Representation of a VLAN which does not exist in the database.
|
||||||
"""
|
"""
|
||||||
vid = serializers.IntegerField(read_only=True)
|
vid = serializers.IntegerField(read_only=True)
|
||||||
group = NestedVLANGroupSerializer(read_only=True)
|
group = VLANGroupSerializer(nested=True, read_only=True)
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
return {
|
return {
|
||||||
'vid': instance,
|
'vid': instance,
|
||||||
'group': NestedVLANGroupSerializer(
|
'group': VLANGroupSerializer(
|
||||||
self.context['group'],
|
self.context['group'],
|
||||||
|
nested=True,
|
||||||
context={'request': self.context['request']}
|
context={'request': self.context['request']}
|
||||||
).data,
|
).data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CreateAvailableVLANSerializer(NetBoxModelSerializer):
|
class CreateAvailableVLANSerializer(NetBoxModelSerializer):
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = SiteSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=VLANStatusChoices, required=False)
|
status = ChoiceField(choices=VLANStatusChoices, required=False)
|
||||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
role = RoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLAN
|
model = VLAN
|
||||||
@ -321,12 +322,12 @@ class CreateAvailableVLANSerializer(NetBoxModelSerializer):
|
|||||||
class PrefixSerializer(NetBoxModelSerializer):
|
class PrefixSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:prefix-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:prefix-detail')
|
||||||
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = SiteSerializer(nested=True, required=False, allow_null=True)
|
||||||
vrf = NestedVRFSerializer(required=False, allow_null=True)
|
vrf = VRFSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
vlan = NestedVLANSerializer(required=False, allow_null=True)
|
vlan = VLANSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=PrefixStatusChoices, required=False)
|
status = ChoiceField(choices=PrefixStatusChoices, required=False)
|
||||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
role = RoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
children = serializers.IntegerField(read_only=True)
|
children = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(read_only=True)
|
_depth = serializers.IntegerField(read_only=True)
|
||||||
prefix = IPNetworkField()
|
prefix = IPNetworkField()
|
||||||
@ -374,11 +375,11 @@ class AvailablePrefixSerializer(serializers.Serializer):
|
|||||||
"""
|
"""
|
||||||
family = serializers.IntegerField(read_only=True)
|
family = serializers.IntegerField(read_only=True)
|
||||||
prefix = serializers.CharField(read_only=True)
|
prefix = serializers.CharField(read_only=True)
|
||||||
vrf = NestedVRFSerializer(read_only=True)
|
vrf = VRFSerializer(nested=True, read_only=True)
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
if self.context.get('vrf'):
|
if self.context.get('vrf'):
|
||||||
vrf = NestedVRFSerializer(self.context['vrf'], context={'request': self.context['request']}).data
|
vrf = VRFSerializer(self.context['vrf'], nested=True, context={'request': self.context['request']}).data
|
||||||
else:
|
else:
|
||||||
vrf = None
|
vrf = None
|
||||||
return {
|
return {
|
||||||
@ -397,10 +398,10 @@ class IPRangeSerializer(NetBoxModelSerializer):
|
|||||||
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
||||||
start_address = IPAddressField()
|
start_address = IPAddressField()
|
||||||
end_address = IPAddressField()
|
end_address = IPAddressField()
|
||||||
vrf = NestedVRFSerializer(required=False, allow_null=True)
|
vrf = VRFSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=IPRangeStatusChoices, required=False)
|
status = ChoiceField(choices=IPRangeStatusChoices, required=False)
|
||||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
role = RoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPRange
|
model = IPRange
|
||||||
@ -420,8 +421,8 @@ class IPAddressSerializer(NetBoxModelSerializer):
|
|||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
|
||||||
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
|
||||||
address = IPAddressField()
|
address = IPAddressField()
|
||||||
vrf = NestedVRFSerializer(required=False, allow_null=True)
|
vrf = VRFSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=IPAddressStatusChoices, required=False)
|
status = ChoiceField(choices=IPAddressStatusChoices, required=False)
|
||||||
role = ChoiceField(choices=IPAddressRoleChoices, allow_blank=True, required=False)
|
role = ChoiceField(choices=IPAddressRoleChoices, allow_blank=True, required=False)
|
||||||
assigned_object_type = ContentTypeField(
|
assigned_object_type = ContentTypeField(
|
||||||
@ -457,12 +458,12 @@ class AvailableIPSerializer(serializers.Serializer):
|
|||||||
"""
|
"""
|
||||||
family = serializers.IntegerField(read_only=True)
|
family = serializers.IntegerField(read_only=True)
|
||||||
address = serializers.CharField(read_only=True)
|
address = serializers.CharField(read_only=True)
|
||||||
vrf = NestedVRFSerializer(read_only=True)
|
vrf = VRFSerializer(nested=True, read_only=True)
|
||||||
description = serializers.CharField(required=False)
|
description = serializers.CharField(required=False)
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
if self.context.get('vrf'):
|
if self.context.get('vrf'):
|
||||||
vrf = NestedVRFSerializer(self.context['vrf'], context={'request': self.context['request']}).data
|
vrf = VRFSerializer(self.context['vrf'], nested=True, context={'request': self.context['request']}).data
|
||||||
else:
|
else:
|
||||||
vrf = None
|
vrf = None
|
||||||
return {
|
return {
|
||||||
@ -491,8 +492,8 @@ class ServiceTemplateSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ServiceSerializer(NetBoxModelSerializer):
|
class ServiceSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:service-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:service-detail')
|
||||||
device = NestedDeviceSerializer(required=False, allow_null=True)
|
device = DeviceSerializer(nested=True, required=False, allow_null=True)
|
||||||
virtual_machine = NestedVirtualMachineSerializer(required=False, allow_null=True)
|
virtual_machine = VirtualMachineSerializer(nested=True, required=False, allow_null=True)
|
||||||
protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
|
protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
|
||||||
ipaddresses = SerializedPKRelatedField(
|
ipaddresses = SerializedPKRelatedField(
|
||||||
queryset=IPAddress.objects.all(),
|
queryset=IPAddress.objects.all(),
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from django.db.models import ManyToManyField
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
|
||||||
|
from utilities.api import get_related_object_by_attrs
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'BaseModelSerializer',
|
'BaseModelSerializer',
|
||||||
'ValidatedModelSerializer',
|
'ValidatedModelSerializer',
|
||||||
@ -12,15 +13,30 @@ __all__ = (
|
|||||||
class BaseModelSerializer(serializers.ModelSerializer):
|
class BaseModelSerializer(serializers.ModelSerializer):
|
||||||
display = serializers.SerializerMethodField(read_only=True)
|
display = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def __init__(self, *args, requested_fields=None, **kwargs):
|
def __init__(self, *args, nested=False, requested_fields=None, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.nested = nested
|
||||||
|
|
||||||
|
if nested and not requested_fields:
|
||||||
|
requested_fields = getattr(self.Meta, 'brief_fields', None)
|
||||||
|
|
||||||
# If specific fields have been requested, omit the others
|
# If specific fields have been requested, omit the others
|
||||||
if requested_fields:
|
if requested_fields:
|
||||||
for field in list(self.fields.keys()):
|
for field in list(self.fields.keys()):
|
||||||
if field not in requested_fields:
|
if field not in requested_fields:
|
||||||
self.fields.pop(field)
|
self.fields.pop(field)
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
|
||||||
|
# If initialized as a nested serializer, we should expect to receive the attrs or PK
|
||||||
|
# identifying a related object.
|
||||||
|
if self.nested:
|
||||||
|
queryset = self.Meta.model.objects.all()
|
||||||
|
return get_related_object_by_attrs(queryset, data)
|
||||||
|
|
||||||
|
return super().to_internal_value(data)
|
||||||
|
|
||||||
@extend_schema_field(OpenApiTypes.STR)
|
@extend_schema_field(OpenApiTypes.STR)
|
||||||
def get_display(self, obj):
|
def get_display(self, obj):
|
||||||
return str(obj)
|
return str(obj)
|
||||||
@ -32,6 +48,11 @@ class ValidatedModelSerializer(BaseModelSerializer):
|
|||||||
validation. (DRF does not do this by default; see https://github.com/encode/django-rest-framework/issues/3144)
|
validation. (DRF does not do this by default; see https://github.com/encode/django-rest-framework/issues/3144)
|
||||||
"""
|
"""
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
|
|
||||||
|
# Skip validation if we're being used to represent a nested object
|
||||||
|
if self.nested:
|
||||||
|
return data
|
||||||
|
|
||||||
attrs = data.copy()
|
attrs = data.copy()
|
||||||
|
|
||||||
# Remove custom field data (if any) prior to model validation
|
# Remove custom field data (if any) prior to model validation
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDoesNotExist
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError
|
|
||||||
|
|
||||||
from extras.models import Tag
|
from extras.models import Tag
|
||||||
from utilities.utils import dict_to_filter_params
|
from utilities.api import get_related_object_by_attrs
|
||||||
from .base import BaseModelSerializer
|
from .base import BaseModelSerializer
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -20,43 +17,8 @@ class WritableNestedSerializer(BaseModelSerializer):
|
|||||||
subclassed to return a full representation of the related object on read.
|
subclassed to return a full representation of the related object on read.
|
||||||
"""
|
"""
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
|
queryset = self.Meta.model.objects.all()
|
||||||
if data is None:
|
return get_related_object_by_attrs(queryset, data)
|
||||||
return None
|
|
||||||
|
|
||||||
# Dictionary of related object attributes
|
|
||||||
if isinstance(data, dict):
|
|
||||||
params = dict_to_filter_params(data)
|
|
||||||
queryset = self.Meta.model.objects
|
|
||||||
try:
|
|
||||||
return queryset.get(**params)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
raise ValidationError(
|
|
||||||
_("Related object not found using the provided attributes: {params}").format(params=params))
|
|
||||||
except MultipleObjectsReturned:
|
|
||||||
raise ValidationError(
|
|
||||||
_("Multiple objects match the provided attributes: {params}").format(params=params)
|
|
||||||
)
|
|
||||||
except FieldError as e:
|
|
||||||
raise ValidationError(e)
|
|
||||||
|
|
||||||
# Integer PK of related object
|
|
||||||
try:
|
|
||||||
# Cast as integer in case a PK was mistakenly sent as a string
|
|
||||||
pk = int(data)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
raise ValidationError(
|
|
||||||
_(
|
|
||||||
"Related objects must be referenced by numeric ID or by dictionary of attributes. Received an "
|
|
||||||
"unrecognized value: {value}"
|
|
||||||
).format(value=data)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Look up object by PK
|
|
||||||
try:
|
|
||||||
return self.Meta.model.objects.get(pk=pk)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
raise ValidationError(_("Related object not found using the provided numeric ID: {id}").format(id=pk))
|
|
||||||
|
|
||||||
|
|
||||||
# Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
|
# Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
|
||||||
|
@ -32,7 +32,7 @@ class TenantGroupSerializer(NestedGroupModelSerializer):
|
|||||||
|
|
||||||
class TenantSerializer(NetBoxModelSerializer):
|
class TenantSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
|
||||||
group = NestedTenantGroupSerializer(required=False, allow_null=True)
|
group = TenantGroupSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
# Related object counts
|
# Related object counts
|
||||||
circuit_count = RelatedObjectCountField('circuits')
|
circuit_count = RelatedObjectCountField('circuits')
|
||||||
@ -87,7 +87,7 @@ class ContactRoleSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ContactSerializer(NetBoxModelSerializer):
|
class ContactSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contact-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contact-detail')
|
||||||
group = NestedContactGroupSerializer(required=False, allow_null=True, default=None)
|
group = ContactGroupSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Contact
|
model = Contact
|
||||||
@ -104,8 +104,8 @@ class ContactAssignmentSerializer(NetBoxModelSerializer):
|
|||||||
queryset=ContentType.objects.all()
|
queryset=ContentType.objects.all()
|
||||||
)
|
)
|
||||||
object = serializers.SerializerMethodField(read_only=True)
|
object = serializers.SerializerMethodField(read_only=True)
|
||||||
contact = NestedContactSerializer()
|
contact = ContactSerializer(nested=True)
|
||||||
role = NestedContactRoleSerializer(required=False, allow_null=True)
|
role = ContactRoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
priority = ChoiceField(choices=ContactPriorityChoices, allow_blank=True, required=False, default=lambda: '')
|
priority = ChoiceField(choices=ContactPriorityChoices, allow_blank=True, required=False, default=lambda: '')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -89,7 +89,7 @@ class TokenSerializer(ValidatedModelSerializer):
|
|||||||
required=False,
|
required=False,
|
||||||
write_only=not settings.ALLOW_TOKEN_RETRIEVAL
|
write_only=not settings.ALLOW_TOKEN_RETRIEVAL
|
||||||
)
|
)
|
||||||
user = NestedUserSerializer()
|
user = UserSerializer(nested=True)
|
||||||
allowed_ips = serializers.ListField(
|
allowed_ips = serializers.ListField(
|
||||||
child=IPNetworkSerializer(),
|
child=IPNetworkSerializer(),
|
||||||
required=False,
|
required=False,
|
||||||
@ -122,7 +122,8 @@ class TokenSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class TokenProvisionSerializer(TokenSerializer):
|
class TokenProvisionSerializer(TokenSerializer):
|
||||||
user = NestedUserSerializer(
|
user = UserSerializer(
|
||||||
|
nested=True,
|
||||||
read_only=True
|
read_only=True
|
||||||
)
|
)
|
||||||
username = serializers.CharField(
|
username = serializers.CharField(
|
||||||
|
@ -3,23 +3,26 @@ import sys
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import (
|
||||||
|
FieldDoesNotExist, FieldError, MultipleObjectsReturned, ObjectDoesNotExist, ValidationError,
|
||||||
|
)
|
||||||
from django.db.models.fields.related import ManyToOneRel, RelatedField
|
from django.db.models.fields.related import ManyToOneRel, RelatedField
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from rest_framework.utils import formatting
|
from rest_framework.utils import formatting
|
||||||
|
|
||||||
from netbox.api.fields import RelatedObjectCountField
|
from netbox.api.fields import RelatedObjectCountField
|
||||||
from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
|
from netbox.api.exceptions import GraphQLTypeNotFound, SerializerNotFound
|
||||||
from utilities.utils import count_related
|
from .utils import count_related, dict_to_filter_params, dynamic_import
|
||||||
from .utils import dynamic_import
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'get_annotations_for_serializer',
|
'get_annotations_for_serializer',
|
||||||
'get_graphql_type_for_model',
|
'get_graphql_type_for_model',
|
||||||
'get_prefetches_for_serializer',
|
'get_prefetches_for_serializer',
|
||||||
|
'get_related_object_by_attrs',
|
||||||
'get_serializer_for_model',
|
'get_serializer_for_model',
|
||||||
'get_view_name',
|
'get_view_name',
|
||||||
'is_api_request',
|
'is_api_request',
|
||||||
@ -103,7 +106,7 @@ def get_prefetches_for_serializer(serializer_class, fields_to_include=None):
|
|||||||
"""
|
"""
|
||||||
model = serializer_class.Meta.model
|
model = serializer_class.Meta.model
|
||||||
|
|
||||||
# If specific fields are not specified, default to all
|
# If fields are not specified, default to all
|
||||||
if not fields_to_include:
|
if not fields_to_include:
|
||||||
fields_to_include = serializer_class.Meta.fields
|
fields_to_include = serializer_class.Meta.fields
|
||||||
|
|
||||||
@ -128,7 +131,9 @@ def get_prefetches_for_serializer(serializer_class, fields_to_include=None):
|
|||||||
# for the related object.
|
# for the related object.
|
||||||
if serializer_field:
|
if serializer_field:
|
||||||
if issubclass(type(serializer_field), Serializer):
|
if issubclass(type(serializer_field), Serializer):
|
||||||
for subfield in get_prefetches_for_serializer(type(serializer_field)):
|
# Determine which fields to prefetch for the nested object
|
||||||
|
subfields = serializer_field.Meta.brief_fields if serializer_field.nested else None
|
||||||
|
for subfield in get_prefetches_for_serializer(type(serializer_field), subfields):
|
||||||
prefetch_fields.append(f'{field_name}__{subfield}')
|
prefetch_fields.append(f'{field_name}__{subfield}')
|
||||||
|
|
||||||
return prefetch_fields
|
return prefetch_fields
|
||||||
@ -154,6 +159,48 @@ def get_annotations_for_serializer(serializer_class, fields_to_include=None):
|
|||||||
return annotations
|
return annotations
|
||||||
|
|
||||||
|
|
||||||
|
def get_related_object_by_attrs(queryset, attrs):
|
||||||
|
"""
|
||||||
|
Return an object identified by either a dictionary of attributes or its numeric primary key (ID). This is used
|
||||||
|
for referencing related objects when creating/updating objects via the REST API.
|
||||||
|
"""
|
||||||
|
if attrs is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Dictionary of related object attributes
|
||||||
|
if isinstance(attrs, dict):
|
||||||
|
params = dict_to_filter_params(attrs)
|
||||||
|
try:
|
||||||
|
return queryset.get(**params)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Related object not found using the provided attributes: {params}").format(params=params))
|
||||||
|
except MultipleObjectsReturned:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Multiple objects match the provided attributes: {params}").format(params=params)
|
||||||
|
)
|
||||||
|
except FieldError as e:
|
||||||
|
raise ValidationError(e)
|
||||||
|
|
||||||
|
# Integer PK of related object
|
||||||
|
try:
|
||||||
|
# Cast as integer in case a PK was mistakenly sent as a string
|
||||||
|
pk = int(attrs)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
raise ValidationError(
|
||||||
|
_(
|
||||||
|
"Related objects must be referenced by numeric ID or by dictionary of attributes. Received an "
|
||||||
|
"unrecognized value: {value}"
|
||||||
|
).format(value=attrs)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Look up object by PK
|
||||||
|
try:
|
||||||
|
return queryset.get(pk=pk)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise ValidationError(_("Related object not found using the provided numeric ID: {id}").format(id=pk))
|
||||||
|
|
||||||
|
|
||||||
def rest_api_server_error(request, *args, **kwargs):
|
def rest_api_server_error(request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Handle exceptions and return a useful error message for REST API requests.
|
Handle exceptions and return a useful error message for REST API requests.
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from dcim.api.nested_serializers import (
|
from dcim.api.serializers import DeviceSerializer, DeviceRoleSerializer, PlatformSerializer, SiteSerializer
|
||||||
NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer,
|
|
||||||
)
|
|
||||||
from dcim.choices import InterfaceModeChoices
|
from dcim.choices import InterfaceModeChoices
|
||||||
from extras.api.nested_serializers import NestedConfigTemplateSerializer
|
from extras.api.serializers import ConfigTemplateSerializer
|
||||||
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
|
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
|
||||||
from ipam.models import VLAN
|
from ipam.models import VLAN
|
||||||
from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
|
from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
|
||||||
from netbox.api.serializers import NetBoxModelSerializer
|
from netbox.api.serializers import NetBoxModelSerializer
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.serializers import TenantSerializer
|
||||||
from virtualization.choices import *
|
from virtualization.choices import *
|
||||||
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualDisk, VirtualMachine, VMInterface
|
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualDisk, VirtualMachine, VMInterface
|
||||||
from vpn.api.nested_serializers import NestedL2VPNTerminationSerializer
|
from vpn.api.nested_serializers import NestedL2VPNTerminationSerializer
|
||||||
@ -53,11 +51,11 @@ class ClusterGroupSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ClusterSerializer(NetBoxModelSerializer):
|
class ClusterSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
|
||||||
type = NestedClusterTypeSerializer()
|
type = ClusterTypeSerializer(nested=True)
|
||||||
group = NestedClusterGroupSerializer(required=False, allow_null=True, default=None)
|
group = ClusterGroupSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
status = ChoiceField(choices=ClusterStatusChoices, required=False)
|
status = ChoiceField(choices=ClusterStatusChoices, required=False)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True, default=None)
|
site = SiteSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
|
|
||||||
# Related object counts
|
# Related object counts
|
||||||
device_count = RelatedObjectCountField('devices')
|
device_count = RelatedObjectCountField('devices')
|
||||||
@ -79,16 +77,16 @@ class ClusterSerializer(NetBoxModelSerializer):
|
|||||||
class VirtualMachineSerializer(NetBoxModelSerializer):
|
class VirtualMachineSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail')
|
||||||
status = ChoiceField(choices=VirtualMachineStatusChoices, required=False)
|
status = ChoiceField(choices=VirtualMachineStatusChoices, required=False)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
site = SiteSerializer(nested=True, required=False, allow_null=True)
|
||||||
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
cluster = ClusterSerializer(nested=True, required=False, allow_null=True)
|
||||||
device = NestedDeviceSerializer(required=False, allow_null=True)
|
device = DeviceSerializer(nested=True, required=False, allow_null=True)
|
||||||
role = NestedDeviceRoleSerializer(required=False, allow_null=True)
|
role = DeviceRoleSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
platform = NestedPlatformSerializer(required=False, allow_null=True)
|
platform = PlatformSerializer(nested=True, required=False, allow_null=True)
|
||||||
primary_ip = NestedIPAddressSerializer(read_only=True)
|
primary_ip = NestedIPAddressSerializer(read_only=True)
|
||||||
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
|
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||||
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||||
config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
|
config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
|
|
||||||
# Counter fields
|
# Counter fields
|
||||||
interface_count = serializers.IntegerField(read_only=True)
|
interface_count = serializers.IntegerField(read_only=True)
|
||||||
@ -128,7 +126,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
|
|||||||
|
|
||||||
class VMInterfaceSerializer(NetBoxModelSerializer):
|
class VMInterfaceSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
|
||||||
virtual_machine = NestedVirtualMachineSerializer()
|
virtual_machine = VirtualMachineSerializer(nested=True)
|
||||||
parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
||||||
bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
|
||||||
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
|
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
|
||||||
@ -178,7 +176,7 @@ class VMInterfaceSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class VirtualDiskSerializer(NetBoxModelSerializer):
|
class VirtualDiskSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualdisk-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualdisk-detail')
|
||||||
virtual_machine = NestedVirtualMachineSerializer()
|
virtual_machine = VirtualMachineSerializer(nested=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualDisk
|
model = VirtualDisk
|
||||||
|
@ -2,12 +2,13 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedRouteTargetSerializer
|
from ipam.api.serializers import IPAddressSerializer
|
||||||
|
from ipam.api.nested_serializers import NestedRouteTargetSerializer
|
||||||
from ipam.models import RouteTarget
|
from ipam.models import RouteTarget
|
||||||
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
|
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField, SerializedPKRelatedField
|
||||||
from netbox.api.serializers import NetBoxModelSerializer
|
from netbox.api.serializers import NetBoxModelSerializer
|
||||||
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.serializers import TenantSerializer
|
||||||
from utilities.api import get_serializer_for_model
|
from utilities.api import get_serializer_for_model
|
||||||
from vpn.choices import *
|
from vpn.choices import *
|
||||||
from vpn.models import *
|
from vpn.models import *
|
||||||
@ -27,90 +28,6 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TunnelGroupSerializer(NetBoxModelSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
|
|
||||||
|
|
||||||
# Related object counts
|
|
||||||
tunnel_count = RelatedObjectCountField('tunnels')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = TunnelGroup
|
|
||||||
fields = [
|
|
||||||
'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
|
|
||||||
'tunnel_count',
|
|
||||||
]
|
|
||||||
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tunnel_count')
|
|
||||||
|
|
||||||
|
|
||||||
class TunnelSerializer(NetBoxModelSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(
|
|
||||||
view_name='vpn-api:tunnel-detail'
|
|
||||||
)
|
|
||||||
status = ChoiceField(
|
|
||||||
choices=TunnelStatusChoices
|
|
||||||
)
|
|
||||||
group = NestedTunnelGroupSerializer(
|
|
||||||
required=False,
|
|
||||||
allow_null=True
|
|
||||||
)
|
|
||||||
encapsulation = ChoiceField(
|
|
||||||
choices=TunnelEncapsulationChoices
|
|
||||||
)
|
|
||||||
ipsec_profile = NestedIPSecProfileSerializer(
|
|
||||||
required=False,
|
|
||||||
allow_null=True
|
|
||||||
)
|
|
||||||
tenant = NestedTenantSerializer(
|
|
||||||
required=False,
|
|
||||||
allow_null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Related object counts
|
|
||||||
terminations_count = RelatedObjectCountField('terminations')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Tunnel
|
|
||||||
fields = (
|
|
||||||
'id', 'url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id',
|
|
||||||
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'terminations_count',
|
|
||||||
)
|
|
||||||
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
|
||||||
|
|
||||||
|
|
||||||
class TunnelTerminationSerializer(NetBoxModelSerializer):
|
|
||||||
url = serializers.HyperlinkedIdentityField(
|
|
||||||
view_name='vpn-api:tunneltermination-detail'
|
|
||||||
)
|
|
||||||
tunnel = NestedTunnelSerializer()
|
|
||||||
role = ChoiceField(
|
|
||||||
choices=TunnelTerminationRoleChoices
|
|
||||||
)
|
|
||||||
termination_type = ContentTypeField(
|
|
||||||
queryset=ContentType.objects.all()
|
|
||||||
)
|
|
||||||
termination = serializers.SerializerMethodField(
|
|
||||||
read_only=True
|
|
||||||
)
|
|
||||||
outside_ip = NestedIPAddressSerializer(
|
|
||||||
required=False,
|
|
||||||
allow_null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = TunnelTermination
|
|
||||||
fields = (
|
|
||||||
'id', 'url', 'display', 'tunnel', 'role', 'termination_type', 'termination_id', '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):
|
|
||||||
serializer = get_serializer_for_model(obj.termination, prefix=NESTED_SERIALIZER_PREFIX)
|
|
||||||
context = {'request': self.context['request']}
|
|
||||||
return serializer(obj.termination, context=context).data
|
|
||||||
|
|
||||||
|
|
||||||
class IKEProposalSerializer(NetBoxModelSerializer):
|
class IKEProposalSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(
|
url = serializers.HyperlinkedIdentityField(
|
||||||
view_name='vpn-api:ikeproposal-detail'
|
view_name='vpn-api:ikeproposal-detail'
|
||||||
@ -215,8 +132,12 @@ class IPSecProfileSerializer(NetBoxModelSerializer):
|
|||||||
mode = ChoiceField(
|
mode = ChoiceField(
|
||||||
choices=IPSecModeChoices
|
choices=IPSecModeChoices
|
||||||
)
|
)
|
||||||
ike_policy = NestedIKEPolicySerializer()
|
ike_policy = IKEPolicySerializer(
|
||||||
ipsec_policy = NestedIPSecPolicySerializer()
|
nested=True
|
||||||
|
)
|
||||||
|
ipsec_policy = IPSecPolicySerializer(
|
||||||
|
nested=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecProfile
|
model = IPSecProfile
|
||||||
@ -227,6 +148,100 @@ class IPSecProfileSerializer(NetBoxModelSerializer):
|
|||||||
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tunnels
|
||||||
|
#
|
||||||
|
|
||||||
|
class TunnelGroupSerializer(NetBoxModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
|
||||||
|
|
||||||
|
# Related object counts
|
||||||
|
tunnel_count = RelatedObjectCountField('tunnels')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TunnelGroup
|
||||||
|
fields = [
|
||||||
|
'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
|
'tunnel_count',
|
||||||
|
]
|
||||||
|
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tunnel_count')
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelSerializer(NetBoxModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(
|
||||||
|
view_name='vpn-api:tunnel-detail'
|
||||||
|
)
|
||||||
|
status = ChoiceField(
|
||||||
|
choices=TunnelStatusChoices
|
||||||
|
)
|
||||||
|
group = TunnelGroupSerializer(
|
||||||
|
nested=True,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
encapsulation = ChoiceField(
|
||||||
|
choices=TunnelEncapsulationChoices
|
||||||
|
)
|
||||||
|
ipsec_profile = IPSecProfileSerializer(
|
||||||
|
nested=True,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
tenant = TenantSerializer(
|
||||||
|
nested=True,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Related object counts
|
||||||
|
terminations_count = RelatedObjectCountField('terminations')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Tunnel
|
||||||
|
fields = (
|
||||||
|
'id', 'url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id',
|
||||||
|
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'terminations_count',
|
||||||
|
)
|
||||||
|
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelTerminationSerializer(NetBoxModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(
|
||||||
|
view_name='vpn-api:tunneltermination-detail'
|
||||||
|
)
|
||||||
|
tunnel = TunnelSerializer(
|
||||||
|
nested=True
|
||||||
|
)
|
||||||
|
role = ChoiceField(
|
||||||
|
choices=TunnelTerminationRoleChoices
|
||||||
|
)
|
||||||
|
termination_type = ContentTypeField(
|
||||||
|
queryset=ContentType.objects.all()
|
||||||
|
)
|
||||||
|
termination = serializers.SerializerMethodField(
|
||||||
|
read_only=True
|
||||||
|
)
|
||||||
|
outside_ip = IPAddressSerializer(
|
||||||
|
nested=True,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TunnelTermination
|
||||||
|
fields = (
|
||||||
|
'id', 'url', 'display', 'tunnel', 'role', 'termination_type', 'termination_id', '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):
|
||||||
|
serializer = get_serializer_for_model(obj.termination, prefix=NESTED_SERIALIZER_PREFIX)
|
||||||
|
context = {'request': self.context['request']}
|
||||||
|
return serializer(obj.termination, context=context).data
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# L2VPN
|
# L2VPN
|
||||||
#
|
#
|
||||||
@ -246,7 +261,7 @@ class L2VPNSerializer(NetBoxModelSerializer):
|
|||||||
required=False,
|
required=False,
|
||||||
many=True
|
many=True
|
||||||
)
|
)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = L2VPN
|
model = L2VPN
|
||||||
@ -259,7 +274,9 @@ class L2VPNSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class L2VPNTerminationSerializer(NetBoxModelSerializer):
|
class L2VPNTerminationSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpntermination-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpntermination-detail')
|
||||||
l2vpn = NestedL2VPNSerializer()
|
l2vpn = L2VPNSerializer(
|
||||||
|
nested=True
|
||||||
|
)
|
||||||
assigned_object_type = ContentTypeField(
|
assigned_object_type = ContentTypeField(
|
||||||
queryset=ContentType.objects.all()
|
queryset=ContentType.objects.all()
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from dcim.choices import LinkStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.api.serializers import NestedInterfaceSerializer
|
from dcim.api.serializers import InterfaceSerializer
|
||||||
from ipam.api.serializers import NestedVLANSerializer
|
from ipam.api.serializers import VLANSerializer
|
||||||
from netbox.api.fields import ChoiceField
|
from netbox.api.fields import ChoiceField
|
||||||
from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
|
from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer
|
||||||
from tenancy.api.nested_serializers import NestedTenantSerializer
|
from tenancy.api.serializers import TenantSerializer
|
||||||
from wireless.choices import *
|
from wireless.choices import *
|
||||||
from wireless.models import *
|
from wireless.models import *
|
||||||
from .nested_serializers import *
|
from .nested_serializers import *
|
||||||
@ -33,10 +33,10 @@ class WirelessLANGroupSerializer(NestedGroupModelSerializer):
|
|||||||
|
|
||||||
class WirelessLANSerializer(NetBoxModelSerializer):
|
class WirelessLANSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
|
||||||
group = NestedWirelessLANGroupSerializer(required=False, allow_null=True)
|
group = WirelessLANGroupSerializer(nested=True, required=False, allow_null=True)
|
||||||
status = ChoiceField(choices=WirelessLANStatusChoices, required=False, allow_blank=True)
|
status = ChoiceField(choices=WirelessLANStatusChoices, required=False, allow_blank=True)
|
||||||
vlan = NestedVLANSerializer(required=False, allow_null=True)
|
vlan = VLANSerializer(nested=True, required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
|
auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
|
||||||
auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
|
auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
|
||||||
|
|
||||||
@ -52,9 +52,9 @@ class WirelessLANSerializer(NetBoxModelSerializer):
|
|||||||
class WirelessLinkSerializer(NetBoxModelSerializer):
|
class WirelessLinkSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
|
||||||
status = ChoiceField(choices=LinkStatusChoices, required=False)
|
status = ChoiceField(choices=LinkStatusChoices, required=False)
|
||||||
interface_a = NestedInterfaceSerializer()
|
interface_a = InterfaceSerializer(nested=True)
|
||||||
interface_b = NestedInterfaceSerializer()
|
interface_b = InterfaceSerializer(nested=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
|
auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
|
||||||
auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
|
auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user