Commit b7ade645 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #25468 -- Made DjangoJSONEncoder lazy string aware

Thanks Stavros Korokithakis for the report and Tim Graham for the
review.
parent 87630bc3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ from django.core.serializers.python import (
    Deserializer as PythonDeserializer, Serializer as PythonSerializer,
)
from django.utils import six
from django.utils.functional import Promise
from django.utils.timezone import is_aware


@@ -111,6 +112,8 @@ class DjangoJSONEncoder(json.JSONEncoder):
            return str(o)
        elif isinstance(o, uuid.UUID):
            return str(o)
        elif isinstance(o, Promise):
            return six.text_type(o)
        else:
            return super(DjangoJSONEncoder, self).default(o)

+6 −0
Original line number Diff line number Diff line
@@ -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
^^^^^^^

+3 −4
Original line number Diff line number Diff line
@@ -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`_.

Be aware that not all Django output can be passed unmodified to :mod:`json`.
In particular, :ref:`lazy translation objects <lazy-translations>` need a
`special encoder`_ written for them. Something like this will work::
For example, if you have some custom type in an object to be serialized, you'll
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.core.serializers.json import DjangoJSONEncoder

    class LazyEncoder(DjangoJSONEncoder):
        def default(self, obj):
            if isinstance(obj, Promise):
            if isinstance(obj, YourCustomType):
                return force_text(obj)
            return super(LazyEncoder, self).default(obj)

+16 −1
Original line number Diff line number Diff line
@@ -6,7 +6,9 @@ import re

from django.core import serializers
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 .tests import SerializersTestBase, SerializersTransactionTestBase
@@ -271,3 +273,16 @@ class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, Transact
            "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"}'
            )