Commit c1b6f554 authored by Berker Peksag's avatar Berker Peksag Committed by Tim Graham
Browse files

Fixed #15091 -- Allowed passing custom encoder to JSON serializer.

parent 6bf79640
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ class Serializer(PythonSerializer):
        if self.options.get('indent'):
            # Prevent trailing spaces
            self.json_kwargs['separators'] = (',', ': ')
        self.json_kwargs.setdefault('cls', DjangoJSONEncoder)

    def start_serialization(self):
        self._init_options()
@@ -58,8 +59,7 @@ class Serializer(PythonSerializer):
                self.stream.write(" ")
        if indent:
            self.stream.write("\n")
        json.dump(self.get_dump_object(obj), self.stream,
                  cls=DjangoJSONEncoder, **self.json_kwargs)
        json.dump(self.get_dump_object(obj), self.stream, **self.json_kwargs)
        self._current = None

    def getvalue(self):
+4 −0
Original line number Diff line number Diff line
@@ -206,6 +206,10 @@ Serialization
* The new ``django.core.serializers.base.Serializer.stream_class`` attribute
  allows subclasses to customize the default stream.

* The encoder used by the :ref:`JSON serializer <serialization-formats-json>`
  can now be customized by passing a ``cls`` keyword argument to the
  ``serializers.serialize()`` function.

Signals
~~~~~~~

+11 −0
Original line number Diff line number Diff line
@@ -265,6 +265,17 @@ work::
                return force_text(obj)
            return super(LazyEncoder, self).default(obj)

You can then pass ``cls=LazyEncoder`` to the ``serializers.serialize()``
function::

    from django.core.serializers import serialize

    serialize('json', SomeModel.objects.all(), cls=LazyEncoder)

.. versionchanged:: 1.11

    The ability to use a custom encoder using ``cls=...`` was added.

Also note that GeoDjango provides a :doc:`customized GeoJSON serializer
</ref/contrib/gis/serializers>`.

+20 −0
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import decimal
import json
import re

from django.core import serializers
from django.core.serializers.base import DeserializationError
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.test import SimpleTestCase, TestCase, TransactionTestCase
from django.test.utils import isolate_apps
from django.utils.translation import override, ugettext_lazy

from .models import Score
@@ -80,6 +83,23 @@ class JsonSerializerTestCase(SerializersTestBase, TestCase):
            if re.search(r'.+,\s*$', line):
                self.assertEqual(line, line.rstrip())

    @isolate_apps('serializers')
    def test_custom_encoder(self):
        class ScoreDecimal(models.Model):
            score = models.DecimalField()

        class CustomJSONEncoder(json.JSONEncoder):
            def default(self, o):
                if isinstance(o, decimal.Decimal):
                    return str(o)
                return super(CustomJSONEncoder, self).default(o)

        s = serializers.json.Serializer()
        json_data = s.serialize(
            [ScoreDecimal(score=decimal.Decimal(1.0))], cls=CustomJSONEncoder
        )
        self.assertIn('"fields": {"score": "1"}', json_data)

    def test_json_deserializer_exception(self):
        with self.assertRaises(DeserializationError):
            for obj in serializers.deserialize("json", """[{"pk":1}"""):