|
@@ -5,6 +5,7 @@ import pytz
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
from django.conf import settings
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
|
+from django.core.exceptions import ObjectDoesNotExist
|
|
|
from django.db.models import ManyToManyField
|
|
from django.db.models import ManyToManyField
|
|
|
from django.http import Http404
|
|
from django.http import Http404
|
|
|
from rest_framework import mixins
|
|
from rest_framework import mixins
|
|
@@ -37,36 +38,9 @@ class IsAuthenticatedOrLoginNotRequired(BasePermission):
|
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
#
|
|
|
-# Serializers
|
|
|
|
|
|
|
+# Fields
|
|
|
#
|
|
#
|
|
|
|
|
|
|
|
-class ValidatedModelSerializer(ModelSerializer):
|
|
|
|
|
- """
|
|
|
|
|
- Extends the built-in ModelSerializer to enforce calling clean() on the associated model during validation.
|
|
|
|
|
- """
|
|
|
|
|
- def validate(self, data):
|
|
|
|
|
-
|
|
|
|
|
- # Remove custom field data (if any) prior to model validation
|
|
|
|
|
- attrs = data.copy()
|
|
|
|
|
- attrs.pop('custom_fields', None)
|
|
|
|
|
-
|
|
|
|
|
- # Run clean() on an instance of the model
|
|
|
|
|
- if self.instance is None:
|
|
|
|
|
- model = self.Meta.model
|
|
|
|
|
- # Ignore ManyToManyFields for new instances (a PK is needed for validation)
|
|
|
|
|
- for field in model._meta.get_fields():
|
|
|
|
|
- if isinstance(field, ManyToManyField) and field.name in attrs:
|
|
|
|
|
- attrs.pop(field.name)
|
|
|
|
|
- instance = self.Meta.model(**attrs)
|
|
|
|
|
- else:
|
|
|
|
|
- instance = self.instance
|
|
|
|
|
- for k, v in attrs.items():
|
|
|
|
|
- setattr(instance, k, v)
|
|
|
|
|
- instance.clean()
|
|
|
|
|
-
|
|
|
|
|
- return data
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
class ChoiceFieldSerializer(Field):
|
|
class ChoiceFieldSerializer(Field):
|
|
|
"""
|
|
"""
|
|
|
Represent a ChoiceField as {'value': <DB value>, 'label': <string>}.
|
|
Represent a ChoiceField as {'value': <DB value>, 'label': <string>}.
|
|
@@ -86,7 +60,7 @@ class ChoiceFieldSerializer(Field):
|
|
|
return {'value': obj, 'label': self._choices[obj]}
|
|
return {'value': obj, 'label': self._choices[obj]}
|
|
|
|
|
|
|
|
def to_internal_value(self, data):
|
|
def to_internal_value(self, data):
|
|
|
- return self._choices.get(data)
|
|
|
|
|
|
|
+ return data
|
|
|
|
|
|
|
|
|
|
|
|
|
class ContentTypeFieldSerializer(Field):
|
|
class ContentTypeFieldSerializer(Field):
|
|
@@ -121,6 +95,48 @@ class TimeZoneField(Field):
|
|
|
raise ValidationError('Invalid time zone "{}"'.format(data))
|
|
raise ValidationError('Invalid time zone "{}"'.format(data))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+#
|
|
|
|
|
+# Serializers
|
|
|
|
|
+#
|
|
|
|
|
+
|
|
|
|
|
+class ValidatedModelSerializer(ModelSerializer):
|
|
|
|
|
+ """
|
|
|
|
|
+ Extends the built-in ModelSerializer to enforce calling clean() on the associated model during validation.
|
|
|
|
|
+ """
|
|
|
|
|
+ def validate(self, data):
|
|
|
|
|
+
|
|
|
|
|
+ # Remove custom field data (if any) prior to model validation
|
|
|
|
|
+ attrs = data.copy()
|
|
|
|
|
+ attrs.pop('custom_fields', None)
|
|
|
|
|
+
|
|
|
|
|
+ # Run clean() on an instance of the model
|
|
|
|
|
+ if self.instance is None:
|
|
|
|
|
+ model = self.Meta.model
|
|
|
|
|
+ # Ignore ManyToManyFields for new instances (a PK is needed for validation)
|
|
|
|
|
+ for field in model._meta.get_fields():
|
|
|
|
|
+ if isinstance(field, ManyToManyField) and field.name in attrs:
|
|
|
|
|
+ attrs.pop(field.name)
|
|
|
|
|
+ instance = self.Meta.model(**attrs)
|
|
|
|
|
+ else:
|
|
|
|
|
+ instance = self.instance
|
|
|
|
|
+ for k, v in attrs.items():
|
|
|
|
|
+ setattr(instance, k, v)
|
|
|
|
|
+ instance.clean()
|
|
|
|
|
+
|
|
|
|
|
+ return data
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class WritableNestedSerializer(ModelSerializer):
|
|
|
|
|
+ """
|
|
|
|
|
+ Returns a nested representation of an object on read, but accepts only a primary key on write.
|
|
|
|
|
+ """
|
|
|
|
|
+ def to_internal_value(self, data):
|
|
|
|
|
+ try:
|
|
|
|
|
+ return self.Meta.model.objects.get(pk=data)
|
|
|
|
|
+ except ObjectDoesNotExist:
|
|
|
|
|
+ raise ValidationError("Invalid ID")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
#
|
|
#
|
|
|
# Viewsets
|
|
# Viewsets
|
|
|
#
|
|
#
|