diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index 261df80f27..ed585faf24 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -25,9 +25,12 @@ The `APIRequestFactory` class supports an almost identical API to Django's stand factory = APIRequestFactory() request = factory.post('/notes/', {'title': 'new idea'}) + # Using the standard RequestFactory API to encode JSON data + request = factory.post('/notes/', {'title': 'new idea'}, content_type='application/json') + #### Using the `format` argument -Methods which create a request body, such as `post`, `put` and `patch`, include a `format` argument, which make it easy to generate requests using a content type other than multipart form data. For example: +Methods which create a request body, such as `post`, `put` and `patch`, include a `format` argument, which make it easy to generate requests using a wide set of request formats. When using this argument, the factory will select an appropriate renderer and its configured `content_type`. For example: # Create a JSON POST request factory = APIRequestFactory() @@ -41,7 +44,7 @@ To support a wider set of request formats, or change the default format, [see th If you need to explicitly encode the request body, you can do so by setting the `content_type` flag. For example: - request = factory.post('/notes/', json.dumps({'title': 'new idea'}), content_type='application/json') + request = factory.post('/notes/', yaml.dump({'title': 'new idea'}), content_type='application/yaml') #### PUT and PATCH with form data diff --git a/rest_framework/test.py b/rest_framework/test.py index e939adcd7e..730b7708e2 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 a7e00ab63e..62dd24dfc6 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -8,9 +8,9 @@ from django.test import TestCase, override_settings from django.urls import path -from rest_framework import fields, serializers +from rest_framework import fields, parsers, serializers from rest_framework.authtoken.models import Token -from rest_framework.decorators import api_view +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 @@ -50,6 +50,12 @@ class BasicSerializer(serializers.Serializer): flag = fields.BooleanField(default=lambda: True) +@api_view(['POST']) +@parser_classes((parsers.JSONParser,)) +def post_json_view(request): + return Response(request.data) + + @api_view(['POST']) def post_view(request): serializer = BasicSerializer(data=request.data) @@ -62,7 +68,8 @@ def post_view(request): path('session-view/', session_view), path('redirect-view/', redirect_view), path('redirect-view//', redirect_307_308_view), - path('post-view/', post_view) + path('post-json-view/', post_json_view), + path('post-view/', post_view), ] @@ -236,6 +243,17 @@ 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' + ) + + assert response.status_code == 200 + assert response.data == data + class TestAPIRequestFactory(TestCase): def test_csrf_exempt_by_default(self): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy