mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 12:06:53 -06:00
Clean up UniqueTogetherValidator workarounds
This commit is contained in:
parent
8375995680
commit
8d0ed99bcd
@ -2,7 +2,6 @@ from django.conf import settings
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from drf_yasg.utils import swagger_serializer_method
|
from drf_yasg.utils import swagger_serializer_method
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.validators import UniqueTogetherValidator
|
|
||||||
from timezone_field.rest_framework import TimeZoneSerializerField
|
from timezone_field.rest_framework import TimeZoneSerializerField
|
||||||
|
|
||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
@ -170,6 +169,8 @@ class RackSerializer(PrimaryModelSerializer):
|
|||||||
status = ChoiceField(choices=RackStatusChoices, required=False)
|
status = ChoiceField(choices=RackStatusChoices, required=False)
|
||||||
role = NestedRackRoleSerializer(required=False, allow_null=True)
|
role = NestedRackRoleSerializer(required=False, allow_null=True)
|
||||||
type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False)
|
type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False)
|
||||||
|
facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label='Facility ID',
|
||||||
|
default=None)
|
||||||
width = ChoiceField(choices=RackWidthChoices, required=False)
|
width = ChoiceField(choices=RackWidthChoices, required=False)
|
||||||
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
|
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
|
||||||
device_count = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
@ -182,23 +183,6 @@ class RackSerializer(PrimaryModelSerializer):
|
|||||||
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
||||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
|
||||||
]
|
]
|
||||||
# Omit the UniqueTogetherValidator that would be automatically added to validate (location, facility_id). This
|
|
||||||
# prevents facility_id from being interpreted as a required field.
|
|
||||||
validators = [
|
|
||||||
UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('location', 'name'))
|
|
||||||
]
|
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
|
|
||||||
# Validate uniqueness of (location, facility_id) since we omitted the automatically-created validator from Meta.
|
|
||||||
if data.get('facility_id', None):
|
|
||||||
validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('location', 'facility_id'))
|
|
||||||
validator(data, self)
|
|
||||||
|
|
||||||
# Enforce model validation
|
|
||||||
super().validate(data)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class RackUnitSerializer(serializers.Serializer):
|
class RackUnitSerializer(serializers.Serializer):
|
||||||
@ -458,12 +442,13 @@ class DeviceSerializer(PrimaryModelSerializer):
|
|||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
|
||||||
device_type = NestedDeviceTypeSerializer()
|
device_type = NestedDeviceTypeSerializer()
|
||||||
device_role = NestedDeviceRoleSerializer()
|
device_role = NestedDeviceRoleSerializer()
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True, default=None)
|
||||||
platform = NestedPlatformSerializer(required=False, allow_null=True)
|
platform = NestedPlatformSerializer(required=False, allow_null=True)
|
||||||
site = NestedSiteSerializer()
|
site = NestedSiteSerializer()
|
||||||
location = NestedLocationSerializer(required=False, allow_null=True, default=None)
|
location = NestedLocationSerializer(required=False, allow_null=True, default=None)
|
||||||
rack = NestedRackSerializer(required=False, allow_null=True)
|
rack = NestedRackSerializer(required=False, allow_null=True, default=None)
|
||||||
face = ChoiceField(choices=DeviceFaceChoices, allow_blank=True, required=False)
|
face = ChoiceField(choices=DeviceFaceChoices, allow_blank=True, default='')
|
||||||
|
position = serializers.IntegerField(allow_null=True, label='Position (U)', min_value=1, default=None)
|
||||||
status = ChoiceField(choices=DeviceStatusChoices, required=False)
|
status = ChoiceField(choices=DeviceStatusChoices, required=False)
|
||||||
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
||||||
primary_ip = NestedIPAddressSerializer(read_only=True)
|
primary_ip = NestedIPAddressSerializer(read_only=True)
|
||||||
@ -471,7 +456,8 @@ class DeviceSerializer(PrimaryModelSerializer):
|
|||||||
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||||
parent_device = serializers.SerializerMethodField()
|
parent_device = serializers.SerializerMethodField()
|
||||||
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
||||||
virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True)
|
virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True, default=None)
|
||||||
|
vc_position = serializers.IntegerField(allow_null=True, max_value=255, min_value=0, default=None)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
@ -481,19 +467,6 @@ class DeviceSerializer(PrimaryModelSerializer):
|
|||||||
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
|
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
|
||||||
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
validators = []
|
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
|
|
||||||
# Validate uniqueness of (rack, position, face) since we omitted the automatically-created validator from Meta.
|
|
||||||
if data.get('rack') and data.get('position') and data.get('face'):
|
|
||||||
validator = UniqueTogetherValidator(queryset=Device.objects.all(), fields=('rack', 'position', 'face'))
|
|
||||||
validator(data, self)
|
|
||||||
|
|
||||||
# Enforce model validation
|
|
||||||
super().validate(data)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
||||||
def get_parent_device(self, obj):
|
def get_parent_device(self, obj):
|
||||||
@ -730,7 +703,6 @@ class DeviceBaySerializer(PrimaryModelSerializer):
|
|||||||
class InventoryItemSerializer(PrimaryModelSerializer):
|
class InventoryItemSerializer(PrimaryModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
|
||||||
device = NestedDeviceSerializer()
|
device = NestedDeviceSerializer()
|
||||||
# Provide a default value to satisfy UniqueTogetherValidator
|
|
||||||
parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
|
parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
|
||||||
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True, default=None)
|
manufacturer = NestedManufacturerSerializer(required=False, allow_null=True, default=None)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='level', read_only=True)
|
||||||
|
@ -3,7 +3,6 @@ from collections import OrderedDict
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from drf_yasg.utils import swagger_serializer_method
|
from drf_yasg.utils import swagger_serializer_method
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.validators import UniqueTogetherValidator
|
|
||||||
|
|
||||||
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerializer
|
from dcim.api.nested_serializers import NestedDeviceSerializer, NestedSiteSerializer
|
||||||
from ipam.choices import *
|
from ipam.choices import *
|
||||||
@ -117,8 +116,10 @@ class VLANGroupSerializer(OrganizationalModelSerializer):
|
|||||||
queryset=ContentType.objects.filter(
|
queryset=ContentType.objects.filter(
|
||||||
model__in=VLANGROUP_SCOPE_TYPES
|
model__in=VLANGROUP_SCOPE_TYPES
|
||||||
),
|
),
|
||||||
required=False
|
required=False,
|
||||||
|
default=None
|
||||||
)
|
)
|
||||||
|
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
|
||||||
scope = serializers.SerializerMethodField(read_only=True)
|
scope = serializers.SerializerMethodField(read_only=True)
|
||||||
vlan_count = serializers.IntegerField(read_only=True)
|
vlan_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
@ -130,19 +131,6 @@ class VLANGroupSerializer(OrganizationalModelSerializer):
|
|||||||
]
|
]
|
||||||
validators = []
|
validators = []
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
|
|
||||||
# Validate uniqueness of name and slug if a site has been assigned.
|
|
||||||
if data.get('site', None):
|
|
||||||
for field in ['name', 'slug']:
|
|
||||||
validator = UniqueTogetherValidator(queryset=VLANGroup.objects.all(), fields=('site', field))
|
|
||||||
validator(data, self)
|
|
||||||
|
|
||||||
# Enforce model validation
|
|
||||||
super().validate(data)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_scope(self, obj):
|
def get_scope(self, obj):
|
||||||
if obj.scope_id is None:
|
if obj.scope_id is None:
|
||||||
return None
|
return None
|
||||||
@ -155,7 +143,7 @@ class VLANGroupSerializer(OrganizationalModelSerializer):
|
|||||||
class VLANSerializer(PrimaryModelSerializer):
|
class VLANSerializer(PrimaryModelSerializer):
|
||||||
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 = NestedSiteSerializer(required=False, allow_null=True)
|
||||||
group = NestedVLANGroupSerializer(required=False, allow_null=True)
|
group = NestedVLANGroupSerializer(required=False, allow_null=True, default=None)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(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 = NestedRoleSerializer(required=False, allow_null=True)
|
||||||
@ -167,20 +155,6 @@ class VLANSerializer(PrimaryModelSerializer):
|
|||||||
'id', 'url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'tags',
|
'id', 'url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'tags',
|
||||||
'custom_fields', 'created', 'last_updated', 'prefix_count',
|
'custom_fields', 'created', 'last_updated', 'prefix_count',
|
||||||
]
|
]
|
||||||
validators = []
|
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
|
|
||||||
# Validate uniqueness of vid and name if a group has been assigned.
|
|
||||||
if data.get('group', None):
|
|
||||||
for field in ['vid', 'name']:
|
|
||||||
validator = UniqueTogetherValidator(queryset=VLAN.objects.all(), fields=('group', field))
|
|
||||||
validator(data, self)
|
|
||||||
|
|
||||||
# Enforce model validation
|
|
||||||
super().validate(data)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user