Allow many, partial and context in BaseSerializer

This commit is contained in:
Tom Christie 2014-09-26 12:48:20 +01:00
parent fde934d33c
commit 8b8623c5f8
3 changed files with 77 additions and 16 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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.