diff options
| -rw-r--r-- | rest_framework/compat.py | 13 | ||||
| -rw-r--r-- | rest_framework/fields.py | 8 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 31 | 
3 files changed, 47 insertions, 5 deletions
| diff --git a/rest_framework/compat.py b/rest_framework/compat.py index cd39f544..76dc0052 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -495,3 +495,16 @@ except ImportError:      oauth2_provider_forms = None      oauth2_provider_scope = None      oauth2_constants = None + +# Handle lazy strings +from django.utils.functional import Promise + +if six.PY3: +    def is_non_str_iterable(obj): +        if (isinstance(obj, str) or +            (isinstance(obj, Promise) and obj._delegate_text)): +            return False +        return hasattr(obj, '__iter__') +else: +    def is_non_str_iterable(obj): +        return hasattr(obj, '__iter__') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index fc14184c..b5f99823 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -26,7 +26,7 @@ from rest_framework import ISO_8601  from rest_framework.compat import timezone, parse_date, parse_datetime, parse_time  from rest_framework.compat import BytesIO  from rest_framework.compat import six -from rest_framework.compat import smart_text +from rest_framework.compat import smart_text, force_text, is_non_str_iterable  from rest_framework.settings import api_settings @@ -45,7 +45,6 @@ def is_simple_callable(obj):      len_defaults = len(defaults) if defaults else 0      return len_args <= len_defaults -  def get_component(obj, attr_name):      """      Given an object, and an attribute name, @@ -169,7 +168,8 @@ class Field(object):          if is_protected_type(value):              return value -        elif hasattr(value, '__iter__') and not isinstance(value, (dict, six.string_types)): +        elif (is_non_str_iterable(value) and +              not isinstance(value, (dict, six.string_types))):              return [self.to_native(item) for item in value]          elif isinstance(value, dict):              # Make sure we preserve field ordering, if it exists @@ -177,7 +177,7 @@ class Field(object):              for key, val in value.items():                  ret[key] = self.to_native(val)              return ret -        return smart_text(value) +        return force_text(value)      def attributes(self):          """ diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index 220a581a..fd6cf6da 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,8 +1,9 @@  from __future__ import unicode_literals  from django.db import models  from django.db.models.fields import BLANK_CHOICE_DASH -from django.utils.datastructures import MultiValueDict  from django.test import TestCase +from django.utils.datastructures import MultiValueDict +from django.utils.translation import ugettext_lazy as _  from rest_framework import serializers  from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel,      BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel, @@ -1323,6 +1324,34 @@ class DeserializeListTestCase(TestCase):          self.assertEqual(serializer.errors, expected) +# test for issue 747 + + +class LazyStringModel(object): +    def __init__(self, lazystring): +        self.lazystring = lazystring + + +class LazyStringSerializer(serializers.Serializer): +    lazystring = serializers.Field() + +    def restore_object(self, attrs, instance=None): +        if instance is not None: +            instance.lazystring = attrs.get('lazystring', instance.lazystring) +            return instance +        return LazyStringModel(**attrs) + + +class LazyStringsTestCase(TestCase): +    def setUp(self): +        self.model = LazyStringModel(lazystring=_('lazystring')) + +    def test_lazy_strings_are_translated(self): +        serializer = LazyStringSerializer(self.model) +        self.assertEqual(type(serializer.data['lazystring']), +                         type('lazystring')) + +  class AttributeMappingOnAutogeneratedFieldsTests(TestCase):      def setUp(self): | 
