From 0a99e02423fe406bfdd9aea50a8d804f7ae07420 Mon Sep 17 00:00:00 2001 From: "Terence D. Honles" Date: Fri, 15 Mar 2019 14:10:42 -0700 Subject: [PATCH] support django 2.1 test client json data automatically serialized --- rest_framework/test.py | 17 +++++++++++++---- tests/test_testing.py | 27 +++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/rest_framework/test.py b/rest_framework/test.py index f2581cacca6..b5f3eb71171 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -151,14 +151,19 @@ def _encode_data(self, data, format=None, content_type=None): Encode the data returning a two tuple of (bytes, content_type) """ - if data is None: - return ('', content_type) - assert format is None or content_type is None, ( 'You may not set both `format` and `content_type`.' ) if content_type: + try: + data = self._encode_json(data, content_type) + except AttributeError: + pass + + if data is None: + data = '' + # Content type specified explicitly, treat data as a raw bytestring ret = force_bytes(data, settings.DEFAULT_CHARSET) @@ -176,7 +181,6 @@ def _encode_data(self, data, format=None, content_type=None): # Use format and render the data into a bytestring renderer = self.renderer_classes[format]() - ret = renderer.render(data) # Determine the content-type header from the renderer content_type = renderer.media_type @@ -185,6 +189,11 @@ def _encode_data(self, data, format=None, content_type=None): content_type, renderer.charset ) + if data is None: + ret = '' + else: + ret = renderer.render(data) + # Coerce text to bytes if required. if isinstance(ret, str): ret = ret.encode(renderer.charset) diff --git a/tests/test_testing.py b/tests/test_testing.py index cc60e4f0030..902b07af7fa 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,12 +1,13 @@ from io import BytesIO +from django import VERSION as DJANGO_VERSION from django.contrib.auth.models import User from django.shortcuts import redirect from django.test import TestCase, override_settings from django.urls import path -from rest_framework import fields, serializers -from rest_framework.decorators import api_view +from rest_framework import fields, parsers, serializers +from rest_framework.decorators import api_view, parser_classes from rest_framework.response import Response from rest_framework.test import ( APIClient, APIRequestFactory, URLPatternsTestCase, force_authenticate @@ -46,11 +47,18 @@ def post_view(request): return Response(serializer.validated_data) +@api_view(['POST']) +@parser_classes((parsers.JSONParser,)) +def post_json_view(request): + return Response(request.data) + + urlpatterns = [ path('view/', view), path('session-view/', session_view), path('redirect-view/', redirect_view), path('post-view/', post_view) + path('post-json-view/', post_json_view), ] @@ -200,6 +208,21 @@ def test_empty_post_uses_default_boolean_value(self): assert response.status_code == 200 assert response.data == {"flag": True} + def test_post_encodes_data_based_on_json_content_type(self): + data = {'data': True} + response = self.client.post( + '/post-json-view/', + data=data, + content_type='application/json' + ) + + if DJANGO_VERSION < (2, 1): + assert response.status_code == 400 + assert response.data['detail'].code == 'parse_error' + else: + assert response.status_code == 200 + assert response.data == data + class TestAPIRequestFactory(TestCase): def test_csrf_exempt_by_default(self):