diff --git a/parler_rest/fields.py b/parler_rest/fields.py index c9afee0..8aa5501 100644 --- a/parler_rest/fields.py +++ b/parler_rest/fields.py @@ -3,6 +3,8 @@ Custom serializer fields for nested translations. """ from __future__ import unicode_literals +import json +from django.utils.six import string_types from django.core.exceptions import ImproperlyConfigured from django.utils.translation import ugettext_lazy as _ @@ -24,6 +26,7 @@ class TranslatedFieldsField(serializers.Field): Exposing all translated fields for a TranslatableModel in REST style. """ default_error_messages = dict(serializers.Field.default_error_messages, **{ + 'invalid_json_dump': _("Input is not a valid json dump"), 'invalid': _("Input is not a valid dict"), 'empty': _("This field may not be empty.") }) @@ -129,6 +132,13 @@ def to_internal_value(self, data): if data is None: return + if isinstance(data, string_types): + # try to convert to json + try: + data = json.loads(data) + except: + self.fail('invalid_json_dump') + if not isinstance(data, dict): self.fail('invalid') if not self.allow_empty and len(data) == 0: diff --git a/setup.py b/setup.py index 8edecd2..efe3b4f 100755 --- a/setup.py +++ b/setup.py @@ -48,6 +48,7 @@ def find_version(*parts): install_requires=[ 'django-parler>=1.2', 'djangorestframework>=3.0', + 'future==0.16.0', ], requires=[ 'Django (>=1.4.2)', diff --git a/testproj/tests.py b/testproj/tests.py index cd4926b..29889a6 100644 --- a/testproj/tests.py +++ b/testproj/tests.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals +import json import unittest from django.test import TestCase @@ -23,7 +24,6 @@ class CountryTranslatedSerializerTestCase(TestCase): - # Disable cache as due to automatic db rollback the instance pk # is the same for all tests and with the cache we'd mistakenly # skips saves after the first test. @@ -98,6 +98,25 @@ def test_translations_validation(self): self.assertTrue(serializer.is_valid(), serializer.errors) six.assertCountEqual(self, serializer.validated_data['translations'], data['translations']) + def test_stringified_translations_validation(self): + translations = { + 'en': { + 'name': "France", + 'url': "http://en.wikipedia.org/wiki/France" + }, + 'es': { + 'name': "Francia", + 'url': "http://es.wikipedia.org/wiki/Francia" + } + } + data = { + 'country_code': 'FR', + 'translations': json.dumps(translations) + } + serializer = CountryTranslatedSerializer(data=data) + self.assertTrue(serializer.is_valid(), serializer.errors) + six.assertCountEqual(self, serializer.validated_data['translations'], translations) + def test_translated_fields_validation(self): data = { 'country_code': 'FR', @@ -119,7 +138,7 @@ def test_translated_fields_validation(self): self.assertIn('url', serializer.errors['translations']['es']) def test_translations_validation_empty(self): - for empty_value in (None, {}, '', ): + for empty_value in (None, {}, '',): data = { 'country_code': 'FR', 'translations': empty_value @@ -128,7 +147,7 @@ def test_translations_validation_empty(self): self.assertFalse(serializer.is_valid()) self.assertIn('translations', serializer.errors) - def test_tranlations_saving_on_create(self): + def test_translations_saving_on_create(self): data = { 'country_code': 'FR', 'translations': { @@ -243,7 +262,6 @@ def test_nested_translated_serializer(self): class ParlerRestUtilsTestCase(unittest.TestCase): - def test_automatic_translation_serializer_creation(self): serializer = create_translated_fields_serializer(Country)() assert serializer.fields["name"]