diff options
Diffstat (limited to 'rest_framework/utils/serializer_helpers.py')
| -rw-r--r-- | rest_framework/utils/serializer_helpers.py | 120 | 
1 files changed, 120 insertions, 0 deletions
| diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py new file mode 100644 index 00000000..87bb3ac0 --- /dev/null +++ b/rest_framework/utils/serializer_helpers.py @@ -0,0 +1,120 @@ +from __future__ import unicode_literals +import collections +from rest_framework.compat import OrderedDict, unicode_to_repr + + +class ReturnDict(OrderedDict): +    """ +    Return object from `serialier.data` for the `Serializer` class. +    Includes a backlink to the serializer instance for renderers +    to use if they need richer field information. +    """ +    def __init__(self, *args, **kwargs): +        self.serializer = kwargs.pop('serializer') +        super(ReturnDict, self).__init__(*args, **kwargs) + +    def copy(self): +        return ReturnDict(self, serializer=self.serializer) + +    def __repr__(self): +        return dict.__repr__(self) + +    def __reduce__(self): +        # Pickling these objects will drop the .serializer backlink, +        # but preserve the raw data. +        return (dict, (dict(self),)) + + +class ReturnList(list): +    """ +    Return object from `serialier.data` for the `SerializerList` class. +    Includes a backlink to the serializer instance for renderers +    to use if they need richer field information. +    """ +    def __init__(self, *args, **kwargs): +        self.serializer = kwargs.pop('serializer') +        super(ReturnList, self).__init__(*args, **kwargs) + +    def __repr__(self): +        return list.__repr__(self) + +    def __reduce__(self): +        # Pickling these objects will drop the .serializer backlink, +        # but preserve the raw data. +        return (list, (list(self),)) + + +class BoundField(object): +    """ +    A field object that also includes `.value` and `.error` properties. +    Returned when iterating over a serializer instance, +    providing an API similar to Django forms and form fields. +    """ +    def __init__(self, field, value, errors, prefix=''): +        self._field = field +        self.value = value +        self.errors = errors +        self.name = prefix + self.field_name + +    def __getattr__(self, attr_name): +        return getattr(self._field, attr_name) + +    @property +    def _proxy_class(self): +        return self._field.__class__ + +    def __repr__(self): +        return unicode_to_repr('<%s value=%s errors=%s>' % ( +            self.__class__.__name__, self.value, self.errors +        )) + + +class NestedBoundField(BoundField): +    """ +    This `BoundField` additionally implements __iter__ and __getitem__ +    in order to support nested bound fields. This class is the type of +    `BoundField` that is used for serializer fields. +    """ +    def __iter__(self): +        for field in self.fields.values(): +            yield self[field.field_name] + +    def __getitem__(self, key): +        field = self.fields[key] +        value = self.value.get(key) if self.value else None +        error = self.errors.get(key) if self.errors else None +        if hasattr(field, 'fields'): +            return NestedBoundField(field, value, error, prefix=self.name + '.') +        return BoundField(field, value, error, prefix=self.name + '.') + + +class BindingDict(collections.MutableMapping): +    """ +    This dict-like object is used to store fields on a serializer. + +    This ensures that whenever fields are added to the serializer we call +    `field.bind()` so that the `field_name` and `parent` attributes +    can be set correctly. +    """ +    def __init__(self, serializer): +        self.serializer = serializer +        self.fields = OrderedDict() + +    def __setitem__(self, key, field): +        self.fields[key] = field +        field.bind(field_name=key, parent=self.serializer) + +    def __getitem__(self, key): +        return self.fields[key] + +    def __delitem__(self, key): +        del self.fields[key] + +    def __iter__(self): +        return iter(self.fields) + +    def __len__(self): +        return len(self.fields) + +    def __repr__(self): +        return dict.__repr__(self.fields) | 
