aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/fields.py17
-rw-r--r--rest_framework/tests/serializer.py31
2 files changed, 44 insertions, 4 deletions
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index fc14184c..d5cf30e4 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -19,6 +19,7 @@ from django.db.models.fields import BLANK_CHOICE_DASH
from django import forms
from django.forms import widgets
from django.utils.encoding import is_protected_type
+from django.utils.functional import Promise
from django.utils.translation import ugettext_lazy as _
from django.utils.datastructures import SortedDict
@@ -26,7 +27,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
from rest_framework.settings import api_settings
@@ -45,6 +46,15 @@ def is_simple_callable(obj):
len_defaults = len(defaults) if defaults else 0
return len_args <= len_defaults
+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__')
def get_component(obj, attr_name):
"""
@@ -169,7 +179,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 +188,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 4f188c3e..759017f4 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):