From a25b4be4418a2a94e38a77b13cc234ca68e8322c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 3 Sep 2012 13:30:20 +0100 Subject: [PATCH] Support generators --- djangorestframework/renderers.py | 5 ++-- djangorestframework/tests/renderers.py | 14 ++++++++++- djangorestframework/utils/encoders.py | 33 ++++++++++++++++++++++++++ docs/tutorial/1-serialization.md | 2 +- 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 djangorestframework/utils/encoders.py diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index 8d1030254..70c0dc88c 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -6,12 +6,12 @@ by serializing the output along with documentation regarding the View, output st and providing forms and links depending on the allowed methods, renderers and parsers on the View. """ from django import forms -from django.core.serializers.json import DateTimeAwareJSONEncoder from django.template import RequestContext, loader from django.utils import simplejson as json from djangorestframework.compat import yaml from djangorestframework.utils import dict2xml +from djangorestframework.utils import encoders from djangorestframework.utils.breadcrumbs import get_breadcrumbs from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches from djangorestframework import VERSION @@ -94,6 +94,7 @@ class JSONRenderer(BaseRenderer): media_type = 'application/json' format = 'json' + encoder_class = encoders.JSONEncoder def render(self, obj=None, media_type=None): """ @@ -112,7 +113,7 @@ class JSONRenderer(BaseRenderer): except (ValueError, TypeError): indent = None - return json.dumps(obj, cls=DateTimeAwareJSONEncoder, indent=indent, sort_keys=sort_keys) + return json.dumps(obj, cls=self.encoder_class, indent=indent, sort_keys=sort_keys) class JSONPRenderer(JSONRenderer): diff --git a/djangorestframework/tests/renderers.py b/djangorestframework/tests/renderers.py index 1943d012b..adf8d8fa1 100644 --- a/djangorestframework/tests/renderers.py +++ b/djangorestframework/tests/renderers.py @@ -22,6 +22,18 @@ RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x +expected_results = [ + ((elem for elem in [1, 2, 3]), JSONRenderer, '[1, 2, 3]') # Generator +] + + +class BasicRendererTests(TestCase): + def test_expected_results(self): + for value, renderer_cls, expected in expected_results: + output = renderer_cls().render(value) + self.assertEquals(output, expected) + + class RendererA(BaseRenderer): media_type = 'mock/renderera' format = "formata" @@ -286,7 +298,7 @@ if YAMLRenderer: obj = {'foo': ['bar', 'baz']} renderer = YAMLRenderer(None) - parser = YAMLParser(None) + parser = YAMLParser() content = renderer.render(obj, 'application/yaml') (data, files) = parser.parse(StringIO(content)) diff --git a/djangorestframework/utils/encoders.py b/djangorestframework/utils/encoders.py new file mode 100644 index 000000000..3cd2e8e11 --- /dev/null +++ b/djangorestframework/utils/encoders.py @@ -0,0 +1,33 @@ +import datetime +import decimal +from django.utils import timezone +from django.utils import simplejson as json + + +class JSONEncoder(json.JSONEncoder): + """ + JSONEncoder subclass that knows how to encode date/time and decimal types. + """ + def default(self, o): + # See "Date Time String Format" in the ECMA-262 specification. + if isinstance(o, datetime.datetime): + r = o.isoformat() + if o.microsecond: + r = r[:23] + r[26:] + if r.endswith('+00:00'): + r = r[:-6] + 'Z' + return r + elif isinstance(o, datetime.date): + return o.isoformat() + elif isinstance(o, datetime.time): + if timezone.is_aware(o): + raise ValueError("JSON can't represent timezone-aware times.") + r = o.isoformat() + if o.microsecond: + r = r[:12] + return r + elif isinstance(o, decimal.Decimal): + return str(o) + elif hasattr(o, '__iter__'): + return [i for i in o] + return super(JSONEncoder, self).default(o) diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 3cfcf8714..13dcb9cce 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -17,7 +17,7 @@ Now that we're inside a virtualenv environment, we can install our package requi pip install django pip install djangorestframework -***Note:** To exit the virtualenv environment at any time, just type `deactivate`. For more information see the [virtualenv documentation][virtualenv].* +**Note:** To exit the virtualenv environment at any time, just type `deactivate`. For more information see the [virtualenv documentation][virtualenv]. ## Getting started