Skip to content

Commit b07d931

Browse files
committed
Merge pull request #2448 from tomchristie/uuid-field
Added UUIDField.
2 parents 47ddbc0 + 889a07f commit b07d931

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

docs/api-guide/fields.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ Corresponds to `django.db.models.fields.URLField`. Uses Django's `django.core.v
182182

183183
**Signature:** `URLField(max_length=200, min_length=None, allow_blank=False)`
184184

185+
## UUIDField
186+
187+
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:
188+
189+
"de305d54-75b4-431b-adb2-eb6b9e546013"
190+
185191
---
186192

187193
# Numeric fields
@@ -320,7 +326,7 @@ Both the `allow_blank` and `allow_null` are valid options on `ChoiceField`, alth
320326

321327
## MultipleChoiceField
322328

323-
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.
329+
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.
324330

325331
**Signature:** `MultipleChoiceField(choices)`
326332

rest_framework/fields.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import decimal
2424
import inspect
2525
import re
26+
import uuid
2627

2728

2829
class empty:
@@ -632,6 +633,23 @@ def __init__(self, **kwargs):
632633
self.validators.append(validator)
633634

634635

636+
class UUIDField(Field):
637+
default_error_messages = {
638+
'invalid': _('"{value}" is not a valid UUID.'),
639+
}
640+
641+
def to_internal_value(self, data):
642+
if not isinstance(data, uuid.UUID):
643+
try:
644+
return uuid.UUID(data)
645+
except (ValueError, TypeError):
646+
self.fail('invalid', value=data)
647+
return data
648+
649+
def to_representation(self, value):
650+
return str(value)
651+
652+
635653
# Number types...
636654

637655
class IntegerField(Field):

rest_framework/serializers.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ class ModelSerializer(Serializer):
702702
you need you should either declare the extra/differing fields explicitly on
703703
the serializer class, or simply use a `Serializer` class.
704704
"""
705+
705706
_field_mapping = ClassLookupDict({
706707
models.AutoField: IntegerField,
707708
models.BigIntegerField: IntegerField,
@@ -724,7 +725,8 @@ class ModelSerializer(Serializer):
724725
models.SmallIntegerField: IntegerField,
725726
models.TextField: CharField,
726727
models.TimeField: TimeField,
727-
models.URLField: URLField,
728+
models.URLField: URLField
729+
# Note: Some version-specific mappings also defined below.
728730
})
729731
_related_class = PrimaryKeyRelatedField
730732

@@ -1132,6 +1134,10 @@ class Meta:
11321134
return NestedSerializer
11331135

11341136

1137+
if hasattr(models, 'UUIDField'):
1138+
ModelSerializer._field_mapping[models.UUIDField] = UUIDField
1139+
1140+
11351141
class HyperlinkedModelSerializer(ModelSerializer):
11361142
"""
11371143
A type of `ModelSerializer` that uses hyperlinked relationships instead

rest_framework/utils/field_mapping.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ def __getitem__(self, key):
3838
return self.mapping[cls]
3939
raise KeyError('Class %s not found in lookup.', cls.__name__)
4040

41+
def __setitem__(self, key, value):
42+
self.mapping[key] = value
43+
4144

4245
def needs_label(model_field, field_name):
4346
"""

tests/test_fields.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import datetime
55
import django
66
import pytest
7+
import uuid
78

89

910
# Tests for field keyword arguments and core functionality.
@@ -467,6 +468,23 @@ class TestURLField(FieldValues):
467468
field = serializers.URLField()
468469

469470

471+
class TestUUIDField(FieldValues):
472+
"""
473+
Valid and invalid values for `UUIDField`.
474+
"""
475+
valid_inputs = {
476+
'825d7aeb-05a9-45b5-a5b7-05df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'),
477+
'825d7aeb05a945b5a5b705df87923cda': uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda')
478+
}
479+
invalid_inputs = {
480+
'825d7aeb-05a9-45b5-a5b7': ['"825d7aeb-05a9-45b5-a5b7" is not a valid UUID.']
481+
}
482+
outputs = {
483+
uuid.UUID('825d7aeb-05a9-45b5-a5b7-05df87923cda'): '825d7aeb-05a9-45b5-a5b7-05df87923cda'
484+
}
485+
field = serializers.UUIDField()
486+
487+
470488
# Number types...
471489

472490
class TestIntegerField(FieldValues):

0 commit comments

Comments
 (0)