aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2014-09-26 12:48:20 +0100
committerTom Christie2014-09-26 12:48:20 +0100
commit8b8623c5f84d443d26804cac52a793a3037a1dd0 (patch)
tree9e39f116b9d224578440261575ec647f1b07a004
parentfde934d33c8692bab5e0e7b6009d358101a25dd7 (diff)
downloaddjango-rest-framework-8b8623c5f84d443d26804cac52a793a3037a1dd0.tar.bz2
Allow many, partial and context in BaseSerializer
-rw-r--r--docs/topics/3.0-announcement.md7
-rw-r--r--rest_framework/serializers.py28
-rw-r--r--tests/test_serializer.py58
3 files changed, 77 insertions, 16 deletions
diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md
index a4e4db14..faba2d35 100644
--- a/docs/topics/3.0-announcement.md
+++ b/docs/topics/3.0-announcement.md
@@ -2,6 +2,13 @@
See the [Version 3.0 GitHub issue](https://github.com/tomchristie/django-rest-framework/pull/1800) for more details.
+Most notable outstanding issues still to resolved on the `version-3.0` branch.
+
+* `FileField` and `ImageField` support.
+* Forms support for serializers and in the browsable API.
+* Enforcing uniqueness on `unique=True` and `unique_together` fields.
+* Optimisations for serialializing primary keys.
+
# REST framework 3.0
The 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views.
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 86bed773..245ec26f 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -47,9 +47,20 @@ class BaseSerializer(Field):
"""
def __init__(self, instance=None, data=None, **kwargs):
- super(BaseSerializer, self).__init__(**kwargs)
self.instance = instance
self._initial_data = data
+ self.partial = kwargs.pop('partial', False)
+ self._context = kwargs.pop('context', {})
+ kwargs.pop('many', None)
+ super(BaseSerializer, self).__init__(**kwargs)
+
+ def __new__(cls, *args, **kwargs):
+ # We override this method in order to automagically create
+ # `ListSerializer` classes instead when `many=True` is set.
+ if kwargs.pop('many', False):
+ kwargs['child'] = cls()
+ return ListSerializer(*args, **kwargs)
+ return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
def to_internal_value(self, data):
raise NotImplementedError('`to_internal_value()` must be implemented.')
@@ -187,10 +198,6 @@ class BindingDict(object):
@six.add_metaclass(SerializerMetaclass)
class Serializer(BaseSerializer):
def __init__(self, *args, **kwargs):
- kwargs.pop('many', None)
- self.partial = kwargs.pop('partial', False)
- self._context = kwargs.pop('context', {})
-
super(Serializer, self).__init__(*args, **kwargs)
# Every new serializer is created with a clone of the field instances.
@@ -200,14 +207,6 @@ class Serializer(BaseSerializer):
for key, value in self._get_base_fields().items():
self.fields[key] = value
- def __new__(cls, *args, **kwargs):
- # We override this method in order to automagically create
- # `ListSerializer` classes instead when `many=True` is set.
- if kwargs.pop('many', False):
- kwargs['child'] = cls()
- return ListSerializer(*args, **kwargs)
- return super(Serializer, cls).__new__(cls, *args, **kwargs)
-
def _get_base_fields(self):
return copy.deepcopy(self._declared_fields)
@@ -296,9 +295,6 @@ class ListSerializer(BaseSerializer):
self.child = kwargs.pop('child', copy.deepcopy(self.child))
assert self.child is not None, '`child` is a required argument.'
assert not inspect.isclass(self.child), '`child` has not been instantiated.'
- self.partial = kwargs.pop('partial', False)
- self._context = kwargs.pop('context', {})
-
super(ListSerializer, self).__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)
diff --git a/tests/test_serializer.py b/tests/test_serializer.py
index 256a12e6..4df1b736 100644
--- a/tests/test_serializer.py
+++ b/tests/test_serializer.py
@@ -43,6 +43,64 @@ class TestSerializer:
serializer.data
+class TestBaseSerializer:
+ def setup(self):
+ class ExampleSerializer(serializers.BaseSerializer):
+ def to_representation(self, obj):
+ return {
+ 'id': obj['id'],
+ 'email': obj['name'] + '@' + obj['domain']
+ }
+
+ def to_internal_value(self, data):
+ name, domain = str(data['email']).split('@')
+ return {
+ 'id': int(data['id']),
+ 'name': name,
+ 'domain': domain,
+ }
+
+ self.Serializer = ExampleSerializer
+
+ def test_serialize_instance(self):
+ instance = {'id': 1, 'name': 'tom', 'domain': 'example.com'}
+ serializer = self.Serializer(instance)
+ assert serializer.data == {'id': 1, 'email': 'tom@example.com'}
+
+ def test_serialize_list(self):
+ instances = [
+ {'id': 1, 'name': 'tom', 'domain': 'example.com'},
+ {'id': 2, 'name': 'ann', 'domain': 'example.com'},
+ ]
+ serializer = self.Serializer(instances, many=True)
+ assert serializer.data == [
+ {'id': 1, 'email': 'tom@example.com'},
+ {'id': 2, 'email': 'ann@example.com'}
+ ]
+
+ def test_validate_data(self):
+ data = {'id': 1, 'email': 'tom@example.com'}
+ serializer = self.Serializer(data=data)
+ assert serializer.is_valid()
+ assert serializer.validated_data == {
+ 'id': 1,
+ 'name': 'tom',
+ 'domain': 'example.com'
+ }
+
+ def test_validate_list(self):
+ data = [
+ {'id': 1, 'email': 'tom@example.com'},
+ {'id': 2, 'email': 'ann@example.com'},
+ ]
+ serializer = self.Serializer(data=data, many=True)
+ assert serializer.is_valid()
+ assert serializer.validated_data == [
+ {'id': 1, 'name': 'tom', 'domain': 'example.com'},
+ {'id': 2, 'name': 'ann', 'domain': 'example.com'}
+ ]
+
+
class TestStarredSource:
"""
Tests for `source='*'` argument, which is used for nested representations.