from __future__ import absolute_import, print_function, unicode_literals
import json
from collections import OrderedDict
import six
from django.conf import settings
from rest_framework import parsers
[docs]class SortedJSONParser(parsers.JSONParser):
"""
Parses JSON-serialized data into OrderedDict.
"""
[docs] def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as JSON and returns the resulting data.
"""
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try:
data = stream.read().decode(encoding)
return json.loads(data, object_pairs_hook=OrderedDict)
except ValueError as exc:
raise parsers.ParseError('JSON parse error - %s' % six.text_type(exc))
# TODO Create a Renderer that does the opposite of this parser.
[docs]class StrippingJSONParser(parsers.JSONParser):
"""
Strip the outer layer of JSON, returning only inner layer.
This is a convenience class, so that API creators do not need
to wrap their serializers in a "parent serializer" for the sole
purpose of stripping out the top-level node.
Place desired root into parser-context as 'parse-root'.
Only supports descending one level of nesting.
Caller is expected to add 'parse_root' to the parser's
context; a convenient place to do this is in a GenericApiView
subclass's `get_parser_context()` method.
Example, for parse_root of "dt_application"::
input json:
{
"dt_application": {
"node1": 1234
}
}
output dictionary:
{
"node1": 1234
}
"""
[docs] def parse(self, stream, media_type=None, parser_context=None):
data = super(StrippingJSONParser, self).parse(
stream, media_type=media_type, parser_context=parser_context
)
try:
root = parser_context.pop('parse_root')
except KeyError:
pass
else:
if root in data:
return data[root]
return data