From e35f0fd3c6203382bf8a8e93a6239a08b4f941ca Mon Sep 17 00:00:00 2001 From: pik Date: Sat, 21 May 2016 15:26:53 +0800 Subject: [PATCH 1/2] Add failing test for webform-input JSONField serializer --- tests/test_serializer.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 741c6ab17..774753613 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -7,13 +7,34 @@ import pytest from rest_framework import serializers from rest_framework.compat import unicode_repr - from .utils import MockObject # Tests for core functionality. # ----------------------------- +from rest_framework.parsers import FormParser, MultiPartParser +from rest_framework.request import Request +from rest_framework import fields +class TestSerialize: + def setup(self): + from rest_framework.test import APIRequestFactory + class DummyJSONSerializer(serializers.Serializer): + json_field = fields.JSONField() + self.factory = APIRequestFactory() + self.Serializer = DummyJSONSerializer + + def test_request_POST_with_form_content_JSONField(self): + data = b'-----------------------------20775962551482475149231161538\r\nContent-Disposition: form-data; name="json_field"\r\n\r\n{"a": true}\r\n-----------------------------20775962551482475149231161538--\r\n' + content_type = 'multipart/form-data; boundary=---------------------------20775962551482475149231161538' + wsgi_request = self.factory.generic('POST', '/', data, content_type) + request = Request(wsgi_request) + request.parsers = (FormParser(), MultiPartParser()) + serializer = self.Serializer(data=request.data) + assert serializer.is_valid(raise_exception=True) == True + assert dict(serializer.data)['json_field'] == {'a': True} + + class TestSerializer: def setup(self): class ExampleSerializer(serializers.Serializer): From 75bb9c5b39874f3a1782bb046629774afc4d836d Mon Sep 17 00:00:00 2001 From: pik Date: Sat, 21 May 2016 11:48:16 +0800 Subject: [PATCH 2/2] Allow JSONField webform-input to support JSON Objects --- rest_framework/fields.py | 10 ++++++++++ rest_framework/renderers.py | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 5eb1b3b4c..502d160b9 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1541,6 +1541,16 @@ class JSONField(Field): self.binary = kwargs.pop('binary', False) super(JSONField, self).__init__(*args, **kwargs) + def get_value(self, dictionary): + """ + If the incoming data is an html-input then it always comes in stringified via. the + multipart/form-input so we should call json.loads on it. + """ + ret = super(JSONField, self).get_value(dictionary) + if html.is_html_input(dictionary): + return json.loads(ret) + return ret + def to_internal_value(self, data): try: if self.binary: diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 63e0d836f..9235d9323 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -30,6 +30,7 @@ from rest_framework.settings import api_settings from rest_framework.utils import encoders from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.field_mapping import ClassLookupDict +from rest_framework.fields import JSONField def zero_as_none(value): @@ -319,9 +320,14 @@ class HTMLFormRenderer(BaseRenderer): style['template_pack'] = parent_style.get('template_pack', self.template_pack) style['renderer'] = self + # If we are rendering a JSON Field we want to convert Python literals to Javascript literals + if issubclass(field._proxy_class, JSONField): + field.value = json.dumps(field.value) + # Get a clone of the field with text-only value representation. field = field.as_form_field() + if style.get('input_type') == 'datetime-local' and isinstance(field.value, six.text_type): field.value = field.value.rstrip('Z')