json.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. """
  2. Serialize data to/from JSON
  3. """
  4. # Avoid shadowing the standard library json module
  5. from __future__ import absolute_import
  6. from __future__ import unicode_literals
  7. import datetime
  8. import decimal
  9. import json
  10. import sys
  11. from django.core.serializers.base import DeserializationError
  12. from django.core.serializers.python import Serializer as PythonSerializer
  13. from django.core.serializers.python import Deserializer as PythonDeserializer
  14. from django.utils import six
  15. from django.utils.timezone import is_aware
  16. class Serializer(PythonSerializer):
  17. """
  18. Convert a queryset to JSON.
  19. """
  20. internal_use_only = False
  21. def start_serialization(self):
  22. if json.__version__.split('.') >= ['2', '1', '3']:
  23. # Use JS strings to represent Python Decimal instances (ticket #16850)
  24. self.options.update({'use_decimal': False})
  25. self._current = None
  26. self.json_kwargs = self.options.copy()
  27. self.json_kwargs.pop('stream', None)
  28. self.json_kwargs.pop('fields', None)
  29. if self.options.get('indent'):
  30. # Prevent trailing spaces
  31. self.json_kwargs['separators'] = (',', ': ')
  32. self.stream.write("[")
  33. def end_serialization(self):
  34. if self.options.get("indent"):
  35. self.stream.write("\n")
  36. self.stream.write("]")
  37. if self.options.get("indent"):
  38. self.stream.write("\n")
  39. def end_object(self, obj):
  40. # self._current has the field data
  41. indent = self.options.get("indent")
  42. if not self.first:
  43. self.stream.write(",")
  44. if not indent:
  45. self.stream.write(" ")
  46. if indent:
  47. self.stream.write("\n")
  48. json.dump(self.get_dump_object(obj), self.stream,
  49. cls=DjangoJSONEncoder, **self.json_kwargs)
  50. self._current = None
  51. def getvalue(self):
  52. # Grand-parent super
  53. return super(PythonSerializer, self).getvalue()
  54. def Deserializer(stream_or_string, **options):
  55. """
  56. Deserialize a stream or string of JSON data.
  57. """
  58. if not isinstance(stream_or_string, (bytes, six.string_types)):
  59. stream_or_string = stream_or_string.read()
  60. if isinstance(stream_or_string, bytes):
  61. stream_or_string = stream_or_string.decode('utf-8')
  62. try:
  63. objects = json.loads(stream_or_string)
  64. for obj in PythonDeserializer(objects, **options):
  65. yield obj
  66. except GeneratorExit:
  67. raise
  68. except Exception as e:
  69. # Map to deserializer error
  70. six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
  71. class DjangoJSONEncoder(json.JSONEncoder):
  72. """
  73. JSONEncoder subclass that knows how to encode date/time and decimal types.
  74. """
  75. def default(self, o):
  76. # See "Date Time String Format" in the ECMA-262 specification.
  77. if isinstance(o, datetime.datetime):
  78. r = o.isoformat()
  79. if o.microsecond:
  80. r = r[:23] + r[26:]
  81. if r.endswith('+00:00'):
  82. r = r[:-6] + 'Z'
  83. return r
  84. elif isinstance(o, datetime.date):
  85. return o.isoformat()
  86. elif isinstance(o, datetime.time):
  87. if is_aware(o):
  88. raise ValueError("JSON can't represent timezone-aware times.")
  89. r = o.isoformat()
  90. if o.microsecond:
  91. r = r[:12]
  92. return r
  93. elif isinstance(o, decimal.Decimal):
  94. return str(o)
  95. else:
  96. return super(DjangoJSONEncoder, self).default(o)
  97. # Older, deprecated class name (for backwards compatibility purposes).
  98. DateTimeAwareJSONEncoder = DjangoJSONEncoder