Fix yaml rendering

This commit is contained in:
Tom Christie 2012-10-10 16:34:00 +01:00
parent 5c7f3e23ee
commit d905d1cbd3
2 changed files with 58 additions and 3 deletions

View File

@ -18,7 +18,7 @@ from rest_framework.utils import encoders
from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework.utils.mediatypes import get_media_type_params from rest_framework.utils.mediatypes import get_media_type_params
from rest_framework import VERSION from rest_framework import VERSION
from rest_framework import serializers from rest_framework import serializers, parsers
class BaseRenderer(object): class BaseRenderer(object):
@ -125,6 +125,7 @@ class YAMLRenderer(BaseRenderer):
media_type = 'application/yaml' media_type = 'application/yaml'
format = 'yaml' format = 'yaml'
encoder = encoders.SafeDumper
def render(self, data, accepted_media_type=None, renderer_context=None): def render(self, data, accepted_media_type=None, renderer_context=None):
""" """
@ -133,7 +134,7 @@ class YAMLRenderer(BaseRenderer):
if data is None: if data is None:
return '' return ''
return yaml.safe_dump(data) return yaml.dump(data, stream=None, Dumper=self.encoder)
class HTMLRenderer(BaseRenderer): class HTMLRenderer(BaseRenderer):
@ -240,7 +241,8 @@ class BrowsableAPIRenderer(BaseRenderer):
if method == 'DELETE' or method == 'OPTIONS': if method == 'DELETE' or method == 'OPTIONS':
return True # Don't actually need to return a form return True # Don't actually need to return a form
if not getattr(view, 'get_serializer', None): if (not getattr(view, 'get_serializer', None) or
not parsers.FormParser in getattr(view, 'parser_classes')):
media_types = [parser.media_type for parser in view.parser_classes] media_types = [parser.media_type for parser in view.parser_classes]
return self.get_generic_content_form(media_types) return self.get_generic_content_form(media_types)

View File

@ -3,8 +3,11 @@ Helper classes for parsers.
""" """
import datetime import datetime
import decimal import decimal
import types
from django.utils import simplejson as json from django.utils import simplejson as json
from django.utils.datastructures import SortedDict
from rest_framework.compat import timezone from rest_framework.compat import timezone
from rest_framework.serializers import DictWithMetadata, SortedDictWithMetadata
class JSONEncoder(json.JSONEncoder): class JSONEncoder(json.JSONEncoder):
@ -36,3 +39,53 @@ class JSONEncoder(json.JSONEncoder):
elif hasattr(o, '__iter__'): elif hasattr(o, '__iter__'):
return [i for i in o] return [i for i in o]
return super(JSONEncoder, self).default(o) return super(JSONEncoder, self).default(o)
try:
import yaml
except ImportError:
SafeDumper = None
else:
# Adapted from http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py
class SafeDumper(yaml.SafeDumper):
"""
Handles decimals as strings.
Handles SortedDicts as usual dicts, but preserves field order, rather
than the usual behaviour of sorting the keys.
"""
def represent_decimal(self, data):
return self.represent_scalar('tag:yaml.org,2002:str', str(data))
def represent_mapping(self, tag, mapping, flow_style=None):
value = []
node = yaml.MappingNode(tag, value, flow_style=flow_style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
best_style = True
if hasattr(mapping, 'items'):
mapping = list(mapping.items())
if not isinstance(mapping, SortedDict):
mapping.sort()
for item_key, item_value in mapping:
node_key = self.represent_data(item_key)
node_value = self.represent_data(item_value)
if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
best_style = False
if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
best_style = False
value.append((node_key, node_value))
if flow_style is None:
if self.default_flow_style is not None:
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style
return node
SafeDumper.add_representer(SortedDict,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(DictWithMetadata,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(SortedDictWithMetadata,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(types.GeneratorType,
yaml.representer.SafeRepresenter.represent_list)