Fixed #25468 -- Made DjangoJSONEncoder lazy string aware

Thanks Stavros Korokithakis for the report and Tim Graham for the
review.
This commit is contained in:
Claude Paroz 2015-09-26 20:15:26 +02:00
parent 87630bc304
commit b7ade64529
4 changed files with 28 additions and 5 deletions

View File

@ -16,6 +16,7 @@ from django.core.serializers.python import (
Deserializer as PythonDeserializer, Serializer as PythonSerializer, Deserializer as PythonDeserializer, Serializer as PythonSerializer,
) )
from django.utils import six from django.utils import six
from django.utils.functional import Promise
from django.utils.timezone import is_aware from django.utils.timezone import is_aware
@ -111,6 +112,8 @@ class DjangoJSONEncoder(json.JSONEncoder):
return str(o) return str(o)
elif isinstance(o, uuid.UUID): elif isinstance(o, uuid.UUID):
return str(o) return str(o)
elif isinstance(o, Promise):
return six.text_type(o)
else: else:
return super(DjangoJSONEncoder, self).default(o) return super(DjangoJSONEncoder, self).default(o)

View File

@ -162,6 +162,12 @@ Requests and Responses
* ... * ...
Serialization
^^^^^^^^^^^^^
* The ``django.core.serializers.json.DjangoJSONEncoder`` now knows how to
serialize lazy strings, typically used for translatable content.
Signals Signals
^^^^^^^ ^^^^^^^

View File

@ -256,16 +256,15 @@ Date and datetime related types are treated in a special way by the JSON
serializer to make the format compatible with `ECMA-262`_. serializer to make the format compatible with `ECMA-262`_.
Be aware that not all Django output can be passed unmodified to :mod:`json`. Be aware that not all Django output can be passed unmodified to :mod:`json`.
In particular, :ref:`lazy translation objects <lazy-translations>` need a For example, if you have some custom type in an object to be serialized, you'll
`special encoder`_ written for them. Something like this will work:: have to write a `special encoder`_ for it. Something like this will work::
from django.utils.functional import Promise
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
class LazyEncoder(DjangoJSONEncoder): class LazyEncoder(DjangoJSONEncoder):
def default(self, obj): def default(self, obj):
if isinstance(obj, Promise): if isinstance(obj, YourCustomType):
return force_text(obj) return force_text(obj)
return super(LazyEncoder, self).default(obj) return super(LazyEncoder, self).default(obj)

View File

@ -6,7 +6,9 @@ import re
from django.core import serializers from django.core import serializers
from django.core.serializers.base import DeserializationError from django.core.serializers.base import DeserializationError
from django.test import TestCase, TransactionTestCase from django.core.serializers.json import DjangoJSONEncoder
from django.test import SimpleTestCase, TestCase, TransactionTestCase
from django.utils.translation import override, ugettext_lazy
from .models import Score from .models import Score
from .tests import SerializersTestBase, SerializersTransactionTestBase from .tests import SerializersTestBase, SerializersTransactionTestBase
@ -271,3 +273,16 @@ class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, Transact
"name": "Agnes" "name": "Agnes"
} }
}]""" }]"""
class DjangoJSONEncoderTests(SimpleTestCase):
def test_lazy_string_encoding(self):
self.assertEqual(
json.dumps({'lang': ugettext_lazy("French")}, cls=DjangoJSONEncoder),
'{"lang": "French"}'
)
with override('fr'):
self.assertEqual(
json.dumps({'lang': ugettext_lazy("French")}, cls=DjangoJSONEncoder),
'{"lang": "Fran\\u00e7ais"}'
)