aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api-guide/fields.md8
-rw-r--r--rest_framework/fields.py18
-rw-r--r--rest_framework/serializers.py8
-rw-r--r--rest_framework/utils/field_mapping.py3
-rw-r--r--tests/test_fields.py18
5 files changed, 53 insertions, 2 deletions
diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md
index b3d274dd..64ec902b 100644
--- a/docs/api-guide/fields.md
+++ b/docs/api-guide/fields.md
@@ -182,6 +182,12 @@ Corresponds to `django.db.models.fields.URLField`. Uses Django's `django.core.v
**Signature:** `URLField(max_length=200, min_length=None, allow_blank=False)`
+## UUIDField
+
+A field that ensures the input is a valid UUID string. The `to_internal_value` method will return a `uuid.UUID` instance. On output the field will return a string in the canonical hyphenated format, for example:
+
+ "de305d54-75b4-431b-adb2-eb6b9e546013"
+
---
# Numeric fields
@@ -320,7 +326,7 @@ Both the `allow_blank` and `allow_null` are valid options on `ChoiceField`, alth
## MultipleChoiceField
-A field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. `to_internal_representation` returns a `set` containing the selected values.
+A field that can accept a set of zero, one or many values, chosen from a limited set of choices. Takes a single mandatory argument. `to_internal_value` returns a `set` containing the selected values.
**Signature:** `MultipleChoiceField(choices)`
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index cc9410aa..5e3f7ce4 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -23,6 +23,7 @@ import datetime
import decimal
import inspect
import re
+import uuid
class empty:
@@ -632,6 +633,23 @@ class URLField(CharField):
self.validators.append(validator)
+class UUIDField(Field):
+ default_error_messages = {
+ 'invalid': _('"{value}" is not a valid UUID.'),
+ }
+
+ def to_internal_value(self, data):
+ if not isinstance(data, uuid.UUID):
+ try:
+ return uuid.UUID(data)
+ except (ValueError, TypeError):
+ self.fail('invalid', value=data)
+ return data
+
+ def to_representation(self, value):
+ return str(value)
+
+
# Number types...
class IntegerField(Field):
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index cf797bdc..dca612ca 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -702,6 +702,7 @@ class ModelSerializer(Serializer):
you need you should either declare the extra/differing fields explicitly on
the serializer class, or simply use a `Serializer` class.
"""
+
_field_mapping = ClassLookupDict({
models.AutoField: IntegerField,
models.BigIntegerField: IntegerField,
@@ -724,7 +725,8 @@ class ModelSerializer(Serializer):
models.SmallIntegerField: IntegerField,
models.TextField: CharField,
models.TimeField: TimeField,
- models.URLField: URLField,
+ models.URLField: URLField
+ # Note: Some version-specific mappings also defined below.
})
_related_class = PrimaryKeyRelatedField
@@ -1132,6 +1134,10 @@ class ModelSerializer(Serializer):
return NestedSerializer
+if hasattr(models, 'UUIDField'):
+ ModelSerializer._field_mapping[models.UUIDField] = UUIDField
+
+
class HyperlinkedModelSerializer(ModelSerializer):
"""
A type of `ModelSerializer` that uses hyperlinked relationships instead
diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py
index cba40d31..c97ec5d0 100644
--- a/rest_framework/utils/field_mapping.py
+++ b/rest_framework/utils/field_mapping.py
@@ -38,6 +38,9 @@ class ClassLookupDict(object):
return self.mapping[cls]
raise KeyError('Class %s not found in lookup.', cls.__name__)
+ def __setitem__(self, key, value):
+ self.mapping[key] = value
+
def needs_label(model_field, field_name):
"""
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 775d4618..a46cc205 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -4,6 +4,7 @@ from rest_framework import serializers
import datetime
import django
import pytest
+import uuid
# Tests for field keyword arguments and core functionality.
@@ -467,6 +468,23 @@ class TestURLField(FieldValues):
field = serializers.URLField()
+class TestUUIDField(FieldValues):
+ """
+ Valid and invalid values for `UUIDField`.
+ """
+ valid_inputs = {
+ '825d7aeb-05a9-45b5-a5b7-05df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'),
+ '825d7aeb05a945b5a5b705df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda')
+ }
+ invalid_inputs = {
+ '825d7aeb-05a9-45b5-a5b7': ['"825d7aeb-05a9-45b5-a5b7" is not a valid UUID.']
+ }
+ outputs = {
+ uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'): '825d7aeb-05a9-45b5-a5b7-05df87923cda'
+ }
+ field = serializers.UUIDField()
+
+
# Number types...
class TestIntegerField(FieldValues):