Browse Source

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

Berker Peksag 8 years ago
parent
commit
c1b6f554e4

+ 2 - 2
django/core/serializers/json.py

@@ -37,6 +37,7 @@ class Serializer(PythonSerializer):
         if self.options.get('indent'):
         if self.options.get('indent'):
             # Prevent trailing spaces
             # Prevent trailing spaces
             self.json_kwargs['separators'] = (',', ': ')
             self.json_kwargs['separators'] = (',', ': ')
+        self.json_kwargs.setdefault('cls', DjangoJSONEncoder)
 
 
     def start_serialization(self):
     def start_serialization(self):
         self._init_options()
         self._init_options()
@@ -58,8 +59,7 @@ class Serializer(PythonSerializer):
                 self.stream.write(" ")
                 self.stream.write(" ")
         if indent:
         if indent:
             self.stream.write("\n")
             self.stream.write("\n")
-        json.dump(self.get_dump_object(obj), self.stream,
+        json.dump(self.get_dump_object(obj), self.stream, **self.json_kwargs)
-                  cls=DjangoJSONEncoder, **self.json_kwargs)
         self._current = None
         self._current = None
 
 
     def getvalue(self):
     def getvalue(self):

+ 4 - 0
docs/releases/1.11.txt

@@ -206,6 +206,10 @@ Serialization
 * The new ``django.core.serializers.base.Serializer.stream_class`` attribute
 * The new ``django.core.serializers.base.Serializer.stream_class`` attribute
   allows subclasses to customize the default stream.
   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
 Signals
 ~~~~~~~
 ~~~~~~~
 
 

+ 11 - 0
docs/topics/serialization.txt

@@ -265,6 +265,17 @@ work::
                 return force_text(obj)
                 return force_text(obj)
             return super(LazyEncoder, self).default(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
 Also note that GeoDjango provides a :doc:`customized GeoJSON serializer
 </ref/contrib/gis/serializers>`.
 </ref/contrib/gis/serializers>`.
 
 

+ 20 - 0
tests/serializers/test_json.py

@@ -1,13 +1,16 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 from __future__ import unicode_literals
 
 
+import decimal
 import json
 import json
 import re
 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.core.serializers.json import DjangoJSONEncoder
 from django.core.serializers.json import DjangoJSONEncoder
+from django.db import models
 from django.test import SimpleTestCase, TestCase, TransactionTestCase
 from django.test import SimpleTestCase, TestCase, TransactionTestCase
+from django.test.utils import isolate_apps
 from django.utils.translation import override, ugettext_lazy
 from django.utils.translation import override, ugettext_lazy
 
 
 from .models import Score
 from .models import Score
@@ -80,6 +83,23 @@ class JsonSerializerTestCase(SerializersTestBase, TestCase):
             if re.search(r'.+,\s*$', line):
             if re.search(r'.+,\s*$', line):
                 self.assertEqual(line, line.rstrip())
                 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):
     def test_json_deserializer_exception(self):
         with self.assertRaises(DeserializationError):
         with self.assertRaises(DeserializationError):
             for obj in serializers.deserialize("json", """[{"pk":1}"""):
             for obj in serializers.deserialize("json", """[{"pk":1}"""):