diff options
| -rw-r--r-- | rest_framework/fields.py | 35 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 6 | ||||
| -rw-r--r-- | tests/test_serializer.py | 33 | 
3 files changed, 61 insertions, 13 deletions
diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 7beccbb7..032bfd04 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -109,8 +109,7 @@ class Field(object):      def __init__(self, read_only=False, write_only=False,                   required=None, default=empty, initial=None, source=None,                   label=None, help_text=None, style=None, -                 error_messages=None, validators=[], allow_null=False, -                 context=None): +                 error_messages=None, validators=[], allow_null=False):          self._creation_counter = Field._creation_counter          Field._creation_counter += 1 @@ -139,7 +138,6 @@ class Field(object):          # These are set up by `.bind()` when the field is added to a serializer.          self.field_name = None          self.parent = None -        self._context = {} if (context is None) else context          # Collect default error message from self and parent classes          messages = {} @@ -163,13 +161,6 @@ class Field(object):          kwargs = copy.deepcopy(self._kwargs)          return self.__class__(*args, **kwargs) -    @property -    def context(self): -        root = self -        while root.parent is not None: -            root = root.parent -        return root._context -      def bind(self, field_name, parent):          """          Setup the context for the field instance. @@ -254,6 +245,8 @@ class Field(object):          """          if data is empty:              if self.required: +                if getattr(self.root, 'partial', False): +                    raise SkipField()                  self.fail('required')              return self.get_default() @@ -304,7 +297,29 @@ class Field(object):              raise AssertionError(msg)          raise ValidationError(msg.format(**kwargs)) +    @property +    def root(self): +        """ +        Returns the top-level serializer for this field. +        """ +        root = self +        while root.parent is not None: +            root = root.parent +        return root + +    @property +    def context(self): +        """ +        Returns the context as passed to the root serializer on initialization. +        """ +        return getattr(self.root, '_context', {}) +      def __repr__(self): +        """ +        Fields are represented using their initial calling arguments. +        This allows us to create descriptive representations for serializer +        instances that show all the declared fields on the serializer. +        """          return representation.field_repr(self) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 04721c7a..b6a1898c 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -181,8 +181,9 @@ class BindingDict(object):  @six.add_metaclass(SerializerMetaclass)  class Serializer(BaseSerializer):      def __init__(self, *args, **kwargs): -        kwargs.pop('partial', None)          kwargs.pop('many', None) +        self.partial = kwargs.pop('partial', False) +        self._context = kwargs.pop('context', {})          super(Serializer, self).__init__(*args, **kwargs) @@ -289,7 +290,8 @@ 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.' -        kwargs.pop('partial', None) +        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 b0eb4e27..5646f994 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -1,3 +1,35 @@ +from rest_framework import serializers + + +# Tests for core functionality. +# ----------------------------- + +class TestSerializer: +    def setup(self): +        class ExampleSerializer(serializers.Serializer): +            char = serializers.CharField() +            integer = serializers.IntegerField() +        self.Serializer = ExampleSerializer + +    def test_valid_serializer(self): +        serializer = self.Serializer(data={'char': 'abc', 'integer': 123}) +        assert serializer.is_valid() +        assert serializer.validated_data == {'char': 'abc', 'integer': 123} +        assert serializer.errors == {} + +    def test_invalid_serializer(self): +        serializer = self.Serializer(data={'char': 'abc'}) +        assert not serializer.is_valid() +        assert serializer.validated_data == {} +        assert serializer.errors == {'integer': ['This field is required.']} + +    def test_partial_validation(self): +        serializer = self.Serializer(data={'char': 'abc'}, partial=True) +        assert serializer.is_valid() +        assert serializer.validated_data == {'char': 'abc'} +        assert serializer.errors == {} + +  # # -*- coding: utf-8 -*-  # from __future__ import unicode_literals  # from django.db import models @@ -334,7 +366,6 @@  #         Check _data attribute is cleared on `save()`  #         Regression test for #1116 -#             — id field is not populated if `data` is accessed prior to `save()`  #         """  #         serializer = ActionItemSerializer(self.actionitem)  #         self.assertIsNone(serializer.data.get('id', None), 'New instance. `id` should not be set.')  | 
