Browse Source

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

Berker Peksag 8 năm trước cách đây
mục cha
commit
c1b6f554e4

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

@@ -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
docs/releases/1.11.txt

@@ -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
docs/topics/serialization.txt

@@ -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
tests/serializers/test_json.py

@@ -1,13 +1,16 @@
 # -*- 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}"""):