Handle empty body with json content-type as json

An empty request body should not imply HTML form semantics.

An attribute in a JSON object can either be:
 - not set at all,
 - null,
 - an empty list.

An HTML form isn't as flexible, so invariably turning an empty body into
a QueryDict makes it impossible to determine if a given value was passed
in as an empty list or if it was not set at all.
This commit is contained in:
Soren Hansen 2015-11-18 00:00:29 +01:00
parent 75a63c2c2e
commit d9a4185920
3 changed files with 15 additions and 2 deletions

View File

@ -62,6 +62,9 @@ class JSONParser(BaseParser):
parser_context = parser_context or {} parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
if not stream:
return {}
try: try:
data = stream.read().decode(encoding) data = stream.read().decode(encoding)
return json.loads(data) return json.loads(data)

View File

@ -275,7 +275,7 @@ class Request(object):
stream = self.stream stream = self.stream
media_type = self.content_type media_type = self.content_type
if stream is None or media_type is None: if stream is None and not media_type:
empty_data = QueryDict('', encoding=self._request._encoding) empty_data = QueryDict('', encoding=self._request._encoding)
empty_files = MultiValueDict() empty_files = MultiValueDict()
return (empty_data, empty_files) return (empty_data, empty_files)

View File

@ -14,7 +14,7 @@ from django.utils import six
from rest_framework import status from rest_framework import status
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser from rest_framework.parsers import BaseParser, FormParser, JSONParser, MultiPartParser
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.test import APIClient, APIRequestFactory from rest_framework.test import APIClient, APIRequestFactory
@ -51,6 +51,16 @@ class TestContentParsing(TestCase):
request = Request(factory.head('/')) request = Request(factory.head('/'))
self.assertEqual(request.data, {}) self.assertEqual(request.data, {})
def test_empty_body_yields_empty_dict_for_json_POST(self):
"""
Ensure request.data returns empty dict for POST request with JSON
content type.
"""
request = Request(factory.post('/', CONTENT_TYPE='application/json'))
request.parsers = (JSONParser(),)
self.assertEquals(type(request.data), dict)
self.assertEquals(request.data, {})
def test_request_DATA_with_form_content(self): def test_request_DATA_with_form_content(self):
""" """
Ensure request.data returns content for POST request with form content. Ensure request.data returns content for POST request with form content.