diff --git a/djangorestframework/compat.py b/djangorestframework/compat.py index 827b4adf5..230172c3d 100644 --- a/djangorestframework/compat.py +++ b/djangorestframework/compat.py @@ -156,6 +156,7 @@ except ImportError: def head(self, request, *args, **kwargs): return self.get(request, *args, **kwargs) +# Markdown is optional try: import markdown import re @@ -204,3 +205,9 @@ try: except ImportError: apply_markdown = None + +# Yaml is optional +try: + import yaml +except ImportError: + yaml = None diff --git a/djangorestframework/parsers.py b/djangorestframework/parsers.py index 37882984c..5f19c521b 100644 --- a/djangorestframework/parsers.py +++ b/djangorestframework/parsers.py @@ -16,15 +16,18 @@ from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParserError from django.utils import simplejson as json from djangorestframework import status +from djangorestframework.compat import yaml from djangorestframework.response import ErrorResponse from djangorestframework.utils.mediatypes import media_type_matches + __all__ = ( 'BaseParser', 'JSONParser', 'PlainTextParser', 'FormParser', 'MultiPartParser', + 'YAMLParser', ) @@ -85,6 +88,27 @@ class JSONParser(BaseParser): {'detail': 'JSON parse error - %s' % unicode(exc)}) +if yaml: + class YAMLParser(BaseParser): + """ + Parses YAML-serialized data. + """ + + media_type = 'application/yaml' + + def parse(self, stream): + """ + Returns a 2-tuple of `(data, files)`. + + `data` will be an object which is the parsed content of the response. + `files` will always be `None`. + """ + try: + return (yaml.safe_load(stream), None) + except ValueError, exc: + raise ErrorResponse(status.HTTP_400_BAD_REQUEST, + {'detail': 'YAML parse error - %s' % unicode(exc)}) + class PlainTextParser(BaseParser): """ diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index e09e2abc5..aae2cab25 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -11,16 +11,14 @@ from django.core.serializers.json import DateTimeAwareJSONEncoder from django.template import RequestContext, loader from django.utils import simplejson as json -from djangorestframework import status -from djangorestframework.compat import apply_markdown + +from djangorestframework.compat import apply_markdown, yaml from djangorestframework.utils import dict2xml, url_resolves from djangorestframework.utils.breadcrumbs import get_breadcrumbs from djangorestframework.utils.description import get_name, get_description from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches from djangorestframework import VERSION -from decimal import Decimal -import re import string from urllib import quote_plus @@ -31,7 +29,8 @@ __all__ = ( 'DocumentingHTMLRenderer', 'DocumentingXHTMLRenderer', 'DocumentingPlainTextRenderer', - 'XMLRenderer' + 'XMLRenderer', + 'YAMLRenderer' ) @@ -131,6 +130,27 @@ class XMLRenderer(BaseRenderer): return dict2xml(obj) +if yaml: + class YAMLRenderer(BaseRenderer): + """ + Renderer which serializes to YAML. + """ + + media_type = 'application/yaml' + format = 'yaml' + + def render(self, obj=None, media_type=None): + """ + Renders *obj* into serialized YAML. + """ + if obj is None: + return '' + + return yaml.dump(obj) +else: + YAMLRenderer = None + + class TemplateRenderer(BaseRenderer): """ A Base class provided for convenience. @@ -361,4 +381,5 @@ DEFAULT_RENDERERS = ( JSONRenderer, DocumentingPlainTextRenderer, XMLRenderer ) - +if YAMLRenderer: + DEFAULT_RENDERERS += (YAMLRenderer,) diff --git a/djangorestframework/templates/renderer.html b/djangorestframework/templates/renderer.html index 5b32d1ec2..3dd5faf3a 100644 --- a/djangorestframework/templates/renderer.html +++ b/djangorestframework/templates/renderer.html @@ -8,6 +8,8 @@ #site-name a {color: #F4F379 !important;} .errorlist {display: inline !important} .errorlist li {display: inline !important; background: white !important; color: black !important; border: 0 !important;} + /* Custom styles */ + .version{font-size:8px;} @@ -18,7 +20,7 @@