Commit 8b8623c5 by Tom Christie

Allow many, partial and context in BaseSerializer

parent fde934d3
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
See the [Version 3.0 GitHub issue](https://github.com/tomchristie/django-rest-framework/pull/1800) for more details. 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 # 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. 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.
......
...@@ -47,9 +47,20 @@ class BaseSerializer(Field): ...@@ -47,9 +47,20 @@ class BaseSerializer(Field):
""" """
def __init__(self, instance=None, data=None, **kwargs): def __init__(self, instance=None, data=None, **kwargs):
super(BaseSerializer, self).__init__(**kwargs)
self.instance = instance self.instance = instance
self._initial_data = data 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): def to_internal_value(self, data):
raise NotImplementedError('`to_internal_value()` must be implemented.') raise NotImplementedError('`to_internal_value()` must be implemented.')
...@@ -187,10 +198,6 @@ class BindingDict(object): ...@@ -187,10 +198,6 @@ class BindingDict(object):
@six.add_metaclass(SerializerMetaclass) @six.add_metaclass(SerializerMetaclass)
class Serializer(BaseSerializer): class Serializer(BaseSerializer):
def __init__(self, *args, **kwargs): 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) super(Serializer, self).__init__(*args, **kwargs)
# Every new serializer is created with a clone of the field instances. # Every new serializer is created with a clone of the field instances.
...@@ -200,14 +207,6 @@ class Serializer(BaseSerializer): ...@@ -200,14 +207,6 @@ class Serializer(BaseSerializer):
for key, value in self._get_base_fields().items(): for key, value in self._get_base_fields().items():
self.fields[key] = value 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): def _get_base_fields(self):
return copy.deepcopy(self._declared_fields) return copy.deepcopy(self._declared_fields)
...@@ -296,9 +295,6 @@ class ListSerializer(BaseSerializer): ...@@ -296,9 +295,6 @@ class ListSerializer(BaseSerializer):
self.child = kwargs.pop('child', copy.deepcopy(self.child)) self.child = kwargs.pop('child', copy.deepcopy(self.child))
assert self.child is not None, '`child` is a required argument.' assert self.child is not None, '`child` is a required argument.'
assert not inspect.isclass(self.child), '`child` has not been instantiated.' 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) super(ListSerializer, self).__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self) self.child.bind(field_name='', parent=self)
......
...@@ -43,6 +43,64 @@ class TestSerializer: ...@@ -43,6 +43,64 @@ class TestSerializer:
serializer.data 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: class TestStarredSource:
""" """
Tests for `source='*'` argument, which is used for nested representations. Tests for `source='*'` argument, which is used for nested representations.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment