mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Fixes #1285: Enforce model validation when creating/editing objects via the API
This commit is contained in:
parent
5b43a108bc
commit
1f9806a480
@ -6,6 +6,7 @@ from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
|
|||||||
from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer
|
from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
from tenancy.api.serializers import NestedTenantSerializer
|
from tenancy.api.serializers import NestedTenantSerializer
|
||||||
|
from utilities.api import ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -44,7 +45,7 @@ class WritableProviderSerializer(CustomFieldModelSerializer):
|
|||||||
# Circuit types
|
# Circuit types
|
||||||
#
|
#
|
||||||
|
|
||||||
class CircuitTypeSerializer(serializers.ModelSerializer):
|
class CircuitTypeSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
@ -110,7 +111,7 @@ class CircuitTerminationSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WritableCircuitTerminationSerializer(serializers.ModelSerializer):
|
class WritableCircuitTerminationSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
|
@ -13,7 +13,7 @@ from dcim.models import (
|
|||||||
)
|
)
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
from tenancy.api.serializers import NestedTenantSerializer
|
from tenancy.api.serializers import NestedTenantSerializer
|
||||||
from utilities.api import ChoiceFieldSerializer
|
from utilities.api import ChoiceFieldSerializer, ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -36,7 +36,7 @@ class RegionSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'name', 'slug', 'parent']
|
fields = ['id', 'name', 'slug', 'parent']
|
||||||
|
|
||||||
|
|
||||||
class WritableRegionSerializer(serializers.ModelSerializer):
|
class WritableRegionSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
@ -98,7 +98,7 @@ class NestedRackGroupSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'url', 'name', 'slug']
|
fields = ['id', 'url', 'name', 'slug']
|
||||||
|
|
||||||
|
|
||||||
class WritableRackGroupSerializer(serializers.ModelSerializer):
|
class WritableRackGroupSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackGroup
|
model = RackGroup
|
||||||
@ -109,7 +109,7 @@ class WritableRackGroupSerializer(serializers.ModelSerializer):
|
|||||||
# Rack roles
|
# Rack roles
|
||||||
#
|
#
|
||||||
|
|
||||||
class RackRoleSerializer(serializers.ModelSerializer):
|
class RackRoleSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
@ -174,6 +174,9 @@ class WritableRackSerializer(CustomFieldModelSerializer):
|
|||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
validator(data)
|
validator(data)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableRackSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -211,7 +214,7 @@ class RackReservationSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'rack', 'units', 'created', 'user', 'description']
|
fields = ['id', 'rack', 'units', 'created', 'user', 'description']
|
||||||
|
|
||||||
|
|
||||||
class WritableRackReservationSerializer(serializers.ModelSerializer):
|
class WritableRackReservationSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
@ -222,7 +225,7 @@ class WritableRackReservationSerializer(serializers.ModelSerializer):
|
|||||||
# Manufacturers
|
# Manufacturers
|
||||||
#
|
#
|
||||||
|
|
||||||
class ManufacturerSerializer(serializers.ModelSerializer):
|
class ManufacturerSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
@ -287,7 +290,7 @@ class ConsolePortTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name']
|
||||||
|
|
||||||
|
|
||||||
class WritableConsolePortTemplateSerializer(serializers.ModelSerializer):
|
class WritableConsolePortTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePortTemplate
|
model = ConsolePortTemplate
|
||||||
@ -306,7 +309,7 @@ class ConsoleServerPortTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name']
|
||||||
|
|
||||||
|
|
||||||
class WritableConsoleServerPortTemplateSerializer(serializers.ModelSerializer):
|
class WritableConsoleServerPortTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPortTemplate
|
model = ConsoleServerPortTemplate
|
||||||
@ -325,7 +328,7 @@ class PowerPortTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name']
|
||||||
|
|
||||||
|
|
||||||
class WritablePowerPortTemplateSerializer(serializers.ModelSerializer):
|
class WritablePowerPortTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPortTemplate
|
model = PowerPortTemplate
|
||||||
@ -344,7 +347,7 @@ class PowerOutletTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name']
|
||||||
|
|
||||||
|
|
||||||
class WritablePowerOutletTemplateSerializer(serializers.ModelSerializer):
|
class WritablePowerOutletTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutletTemplate
|
model = PowerOutletTemplate
|
||||||
@ -364,7 +367,7 @@ class InterfaceTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
|
fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
|
||||||
|
|
||||||
|
|
||||||
class WritableInterfaceTemplateSerializer(serializers.ModelSerializer):
|
class WritableInterfaceTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InterfaceTemplate
|
model = InterfaceTemplate
|
||||||
@ -383,7 +386,7 @@ class DeviceBayTemplateSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name']
|
||||||
|
|
||||||
|
|
||||||
class WritableDeviceBayTemplateSerializer(serializers.ModelSerializer):
|
class WritableDeviceBayTemplateSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBayTemplate
|
model = DeviceBayTemplate
|
||||||
@ -394,7 +397,7 @@ class WritableDeviceBayTemplateSerializer(serializers.ModelSerializer):
|
|||||||
# Device roles
|
# Device roles
|
||||||
#
|
#
|
||||||
|
|
||||||
class DeviceRoleSerializer(serializers.ModelSerializer):
|
class DeviceRoleSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
@ -413,7 +416,7 @@ class NestedDeviceRoleSerializer(serializers.ModelSerializer):
|
|||||||
# Platforms
|
# Platforms
|
||||||
#
|
#
|
||||||
|
|
||||||
class PlatformSerializer(serializers.ModelSerializer):
|
class PlatformSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
@ -496,6 +499,9 @@ class WritableDeviceSerializer(CustomFieldModelSerializer):
|
|||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
validator(data)
|
validator(data)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableDeviceSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -512,7 +518,7 @@ class ConsoleServerPortSerializer(serializers.ModelSerializer):
|
|||||||
read_only_fields = ['connected_console']
|
read_only_fields = ['connected_console']
|
||||||
|
|
||||||
|
|
||||||
class WritableConsoleServerPortSerializer(serializers.ModelSerializer):
|
class WritableConsoleServerPortSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPort
|
model = ConsoleServerPort
|
||||||
@ -532,7 +538,7 @@ class ConsolePortSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
|
fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class WritableConsolePortSerializer(serializers.ModelSerializer):
|
class WritableConsolePortSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePort
|
model = ConsolePort
|
||||||
@ -552,7 +558,7 @@ class PowerOutletSerializer(serializers.ModelSerializer):
|
|||||||
read_only_fields = ['connected_port']
|
read_only_fields = ['connected_port']
|
||||||
|
|
||||||
|
|
||||||
class WritablePowerOutletSerializer(serializers.ModelSerializer):
|
class WritablePowerOutletSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
@ -572,7 +578,7 @@ class PowerPortSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
|
fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class WritablePowerPortSerializer(serializers.ModelSerializer):
|
class WritablePowerPortSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPort
|
model = PowerPort
|
||||||
@ -630,7 +636,7 @@ class PeerInterfaceSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WritableInterfaceSerializer(serializers.ModelSerializer):
|
class WritableInterfaceSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
@ -652,7 +658,7 @@ class DeviceBaySerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device', 'name', 'installed_device']
|
fields = ['id', 'device', 'name', 'installed_device']
|
||||||
|
|
||||||
|
|
||||||
class WritableDeviceBaySerializer(serializers.ModelSerializer):
|
class WritableDeviceBaySerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
@ -675,7 +681,7 @@ class InventoryItemSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WritableInventoryItemSerializer(serializers.ModelSerializer):
|
class WritableInventoryItemSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
@ -707,7 +713,7 @@ class NestedInterfaceConnectionSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'url', 'connection_status']
|
fields = ['id', 'url', 'connection_status']
|
||||||
|
|
||||||
|
|
||||||
class WritableInterfaceConnectionSerializer(serializers.ModelSerializer):
|
class WritableInterfaceConnectionSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InterfaceConnection
|
model = InterfaceConnection
|
||||||
|
@ -111,6 +111,16 @@ class CustomFieldModelSerializer(serializers.ModelSerializer):
|
|||||||
defaults={'serialized_value': custom_field.serialize_value(value)},
|
defaults={'serialized_value': custom_field.serialize_value(value)},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
"""
|
||||||
|
Enforce model validation (see utilities.api.ModelValidationMixin)
|
||||||
|
"""
|
||||||
|
model_data = data.copy()
|
||||||
|
model_data.pop('custom_fields', None)
|
||||||
|
instance = self.Meta.model(**model_data)
|
||||||
|
instance.clean()
|
||||||
|
return data
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
|
||||||
custom_fields = validated_data.pop('custom_fields', None)
|
custom_fields = validated_data.pop('custom_fields', None)
|
||||||
|
@ -10,7 +10,7 @@ from extras.models import (
|
|||||||
ACTION_CHOICES, ExportTemplate, Graph, GRAPH_TYPE_CHOICES, ImageAttachment, TopologyMap, UserAction,
|
ACTION_CHOICES, ExportTemplate, Graph, GRAPH_TYPE_CHOICES, ImageAttachment, TopologyMap, UserAction,
|
||||||
)
|
)
|
||||||
from users.api.serializers import NestedUserSerializer
|
from users.api.serializers import NestedUserSerializer
|
||||||
from utilities.api import ChoiceFieldSerializer, ContentTypeFieldSerializer
|
from utilities.api import ChoiceFieldSerializer, ContentTypeFieldSerializer, ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -104,7 +104,7 @@ class ImageAttachmentSerializer(serializers.ModelSerializer):
|
|||||||
return serializer(obj.parent, context={'request': self.context['request']}).data
|
return serializer(obj.parent, context={'request': self.context['request']}).data
|
||||||
|
|
||||||
|
|
||||||
class WritableImageAttachmentSerializer(serializers.ModelSerializer):
|
class WritableImageAttachmentSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
content_type = ContentTypeFieldSerializer()
|
content_type = ContentTypeFieldSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -121,6 +121,9 @@ class WritableImageAttachmentSerializer(serializers.ModelSerializer):
|
|||||||
"Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
|
"Invalid parent object: {} ID {}".format(data['content_type'], data['object_id'])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableImageAttachmentSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ from ipam.models import (
|
|||||||
PREFIX_STATUS_CHOICES, RIR, Role, Service, VLAN, VLAN_STATUS_CHOICES, VLANGroup, VRF,
|
PREFIX_STATUS_CHOICES, RIR, Role, Service, VLAN, VLAN_STATUS_CHOICES, VLANGroup, VRF,
|
||||||
)
|
)
|
||||||
from tenancy.api.serializers import NestedTenantSerializer
|
from tenancy.api.serializers import NestedTenantSerializer
|
||||||
from utilities.api import ChoiceFieldSerializer
|
from utilities.api import ChoiceFieldSerializer, ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -45,7 +45,7 @@ class WritableVRFSerializer(CustomFieldModelSerializer):
|
|||||||
# Roles
|
# Roles
|
||||||
#
|
#
|
||||||
|
|
||||||
class RoleSerializer(serializers.ModelSerializer):
|
class RoleSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Role
|
model = Role
|
||||||
@ -64,7 +64,7 @@ class NestedRoleSerializer(serializers.ModelSerializer):
|
|||||||
# RIRs
|
# RIRs
|
||||||
#
|
#
|
||||||
|
|
||||||
class RIRSerializer(serializers.ModelSerializer):
|
class RIRSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RIR
|
model = RIR
|
||||||
@ -142,6 +142,9 @@ class WritableVLANGroupSerializer(serializers.ModelSerializer):
|
|||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
validator(data)
|
validator(data)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableVLANGroupSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -188,6 +191,9 @@ class WritableVLANSerializer(CustomFieldModelSerializer):
|
|||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
validator(data)
|
validator(data)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableVLANSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@ -297,6 +303,7 @@ class ServiceSerializer(serializers.ModelSerializer):
|
|||||||
fields = ['id', 'device', 'name', 'port', 'protocol', 'ipaddresses', 'description']
|
fields = ['id', 'device', 'name', 'port', 'protocol', 'ipaddresses', 'description']
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Figure out how to use ModelValidationMixin with ManyToManyFields. Calling clean() yields a ValueError.
|
||||||
class WritableServiceSerializer(serializers.ModelSerializer):
|
class WritableServiceSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -5,13 +5,14 @@ from rest_framework.validators import UniqueTogetherValidator
|
|||||||
|
|
||||||
from dcim.api.serializers import NestedDeviceSerializer
|
from dcim.api.serializers import NestedDeviceSerializer
|
||||||
from secrets.models import Secret, SecretRole
|
from secrets.models import Secret, SecretRole
|
||||||
|
from utilities.api import ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# SecretRoles
|
# SecretRoles
|
||||||
#
|
#
|
||||||
|
|
||||||
class SecretRoleSerializer(serializers.ModelSerializer):
|
class SecretRoleSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SecretRole
|
model = SecretRole
|
||||||
@ -55,4 +56,7 @@ class WritableSecretSerializer(serializers.ModelSerializer):
|
|||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
validator(data)
|
validator(data)
|
||||||
|
|
||||||
|
# Enforce model validation
|
||||||
|
super(WritableSecretSerializer, self).validate(data)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -4,13 +4,14 @@ from rest_framework import serializers
|
|||||||
|
|
||||||
from extras.api.customfields import CustomFieldModelSerializer
|
from extras.api.customfields import CustomFieldModelSerializer
|
||||||
from tenancy.models import Tenant, TenantGroup
|
from tenancy.models import Tenant, TenantGroup
|
||||||
|
from utilities.api import ModelValidationMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Tenant groups
|
# Tenant groups
|
||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupSerializer(serializers.ModelSerializer):
|
class TenantGroupSerializer(ModelValidationMixin, serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
|
@ -98,6 +98,17 @@ class ContentTypeFieldSerializer(Field):
|
|||||||
raise ValidationError("Invalid content type")
|
raise ValidationError("Invalid content type")
|
||||||
|
|
||||||
|
|
||||||
|
class ModelValidationMixin(object):
|
||||||
|
"""
|
||||||
|
Enforce a model's validation through clean() when validating serializer data. This is necessary to ensure we're
|
||||||
|
employing the same validation logic via both forms and the API.
|
||||||
|
"""
|
||||||
|
def validate(self, attrs):
|
||||||
|
instance = self.Meta.model(**attrs)
|
||||||
|
instance.clean()
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class WritableSerializerMixin(object):
|
class WritableSerializerMixin(object):
|
||||||
"""
|
"""
|
||||||
Allow for the use of an alternate, writable serializer class for write operations (e.g. POST, PUT).
|
Allow for the use of an alternate, writable serializer class for write operations (e.g. POST, PUT).
|
||||||
|
Loading…
Reference in New Issue
Block a user