diff --git a/netbox/ipam/api/nested_serializers.py b/netbox/ipam/api/nested_serializers.py index 57bb58b5ed..0865e45014 100644 --- a/netbox/ipam/api/nested_serializers.py +++ b/netbox/ipam/api/nested_serializers.py @@ -1,11 +1,14 @@ +from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema_serializer from rest_framework import serializers from ipam import models from ipam.models.l2vpn import L2VPNTermination, L2VPN +from ipam.validators import validate_ipaddress_with_mask from netbox.api.serializers import WritableNestedSerializer __all__ = [ + 'IPAddressField', 'NestedAggregateSerializer', 'NestedASNSerializer', 'NestedASNRangeSerializer', @@ -27,6 +30,23 @@ ] +# +# IP address field +# + +class IPAddressField(serializers.CharField): + """IPAddressField with mask""" + + default_error_messages = { + 'invalid': _('Enter a valid IPv4 or IPv6 address with optional mask.'), + } + + def __init__(self, **kwargs): + super().__init__(**kwargs) + validator = validate_ipaddress_with_mask + self.validators.append(validator) + + # # ASN ranges # @@ -182,6 +202,8 @@ class Meta: class NestedIPRangeSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='ipam-api:iprange-detail') family = serializers.IntegerField(read_only=True) + start_address = IPAddressField() + end_address = IPAddressField() class Meta: model = models.IPRange @@ -195,6 +217,7 @@ class Meta: class NestedIPAddressSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail') family = serializers.IntegerField(read_only=True) + address = IPAddressField() class Meta: model = models.IPAddress diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index 220bafa8ed..4aa0a75de9 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -1,5 +1,4 @@ from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema_field from rest_framework import serializers @@ -7,7 +6,6 @@ from ipam.choices import * from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS, VLANGROUP_SCOPE_TYPES from ipam.models import * -from ipam.validators import validate_ipaddress_with_mask from netaddr import AddrFormatError, IPNetwork from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.serializers import NetBoxModelSerializer @@ -372,6 +370,8 @@ def to_representation(self, instance): class IPRangeSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='ipam-api:iprange-detail') family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) + start_address = IPAddressField() + end_address = IPAddressField() vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) status = ChoiceField(choices=IPRangeStatusChoices, required=False) @@ -390,18 +390,6 @@ class Meta: # # IP addresses # -class IPAddressField(serializers.CharField): - """IPAddressField with mask""" - - default_error_messages = { - 'invalid': _('Enter a valid IPv4 or IPv6 address with optional mask.'), - } - - def __init__(self, **kwargs): - super().__init__(**kwargs) - validator = validate_ipaddress_with_mask - self.validators.append(validator) - class IPAddressSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')