Fixed #29687 -- Allowed the test client to serialize list/tuple as JSON.
This commit is contained in:
parent
08f788b169
commit
e181666973
1
AUTHORS
1
AUTHORS
|
@ -206,6 +206,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Daniel Wiesmann <daniel.wiesmann@gmail.com>
|
Daniel Wiesmann <daniel.wiesmann@gmail.com>
|
||||||
Danilo Bargen
|
Danilo Bargen
|
||||||
Dan Johnson <danj.py@gmail.com>
|
Dan Johnson <danj.py@gmail.com>
|
||||||
|
Dan Palmer <dan@danpalmer.me>
|
||||||
Dan Poirier <poirier@pobox.com>
|
Dan Poirier <poirier@pobox.com>
|
||||||
Dan Stephenson <http://dan.io/>
|
Dan Stephenson <http://dan.io/>
|
||||||
Dan Watson <http://danwatson.net/>
|
Dan Watson <http://danwatson.net/>
|
||||||
|
|
|
@ -317,10 +317,10 @@ class RequestFactory:
|
||||||
|
|
||||||
def _encode_json(self, data, content_type):
|
def _encode_json(self, data, content_type):
|
||||||
"""
|
"""
|
||||||
Return encoded JSON if data is a dict and content_type is
|
Return encoded JSON if data is a dict, list, or tuple and content_type
|
||||||
application/json.
|
is application/json.
|
||||||
"""
|
"""
|
||||||
should_encode = JSON_CONTENT_TYPE_RE.match(content_type) and isinstance(data, dict)
|
should_encode = JSON_CONTENT_TYPE_RE.match(content_type) and isinstance(data, (dict, list, tuple))
|
||||||
return json.dumps(data, cls=self.json_encoder) if should_encode else data
|
return json.dumps(data, cls=self.json_encoder) if should_encode else data
|
||||||
|
|
||||||
def _get_path(self, parsed):
|
def _get_path(self, parsed):
|
||||||
|
|
|
@ -224,6 +224,10 @@ Tests
|
||||||
URL, ignoring the ordering of the query string.
|
URL, ignoring the ordering of the query string.
|
||||||
:meth:`~.SimpleTestCase.assertRedirects` uses the new assertion.
|
:meth:`~.SimpleTestCase.assertRedirects` uses the new assertion.
|
||||||
|
|
||||||
|
* The test :class:`~.django.test.Client` now supports automatic JSON
|
||||||
|
serialization of list and tuple ``data`` when
|
||||||
|
``content_type='application/json'``.
|
||||||
|
|
||||||
URLs
|
URLs
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
@ -213,10 +213,11 @@ Use the ``django.test.Client`` class to make requests.
|
||||||
|
|
||||||
name=fred&passwd=secret
|
name=fred&passwd=secret
|
||||||
|
|
||||||
If you provide ``content_type`` as :mimetype:`application/json`, a
|
If you provide ``content_type`` as :mimetype:`application/json`, the
|
||||||
``data`` dictionary is serialized using :func:`json.dumps` with
|
``data`` is serialized using :func:`json.dumps` if it's a dict, list,
|
||||||
:class:`~django.core.serializers.json.DjangoJSONEncoder`. You can
|
or tuple. Serialization is performed with
|
||||||
change the encoder by providing a ``json_encoder`` argument to
|
:class:`~django.core.serializers.json.DjangoJSONEncoder` by default,
|
||||||
|
and can be overridden by providing a ``json_encoder`` argument to
|
||||||
:class:`Client`. This serialization also happens for :meth:`put`,
|
:class:`Client`. This serialization also happens for :meth:`put`,
|
||||||
:meth:`patch`, and :meth:`delete` requests.
|
:meth:`patch`, and :meth:`delete` requests.
|
||||||
|
|
||||||
|
@ -226,6 +227,11 @@ Use the ``django.test.Client`` class to make requests.
|
||||||
you can call :func:`json.dumps` on ``data`` before passing it to
|
you can call :func:`json.dumps` on ``data`` before passing it to
|
||||||
``post()`` to achieve the same thing.
|
``post()`` to achieve the same thing.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.2
|
||||||
|
|
||||||
|
The JSON serialization was extended to support lists and tuples. In
|
||||||
|
older versions, only dicts are serialized.
|
||||||
|
|
||||||
If you provide any other ``content_type`` (e.g. :mimetype:`text/xml`
|
If you provide any other ``content_type`` (e.g. :mimetype:`text/xml`
|
||||||
for an XML payload), the contents of ``data`` are sent as-is in the
|
for an XML payload), the contents of ``data`` are sent as-is in the
|
||||||
POST request, using ``content_type`` in the HTTP ``Content-Type``
|
POST request, using ``content_type`` in the HTTP ``Content-Type``
|
||||||
|
|
|
@ -95,14 +95,21 @@ class ClientTest(TestCase):
|
||||||
def test_json_serialization(self):
|
def test_json_serialization(self):
|
||||||
"""The test client serializes JSON data."""
|
"""The test client serializes JSON data."""
|
||||||
methods = ('post', 'put', 'patch', 'delete')
|
methods = ('post', 'put', 'patch', 'delete')
|
||||||
|
tests = (
|
||||||
|
({'value': 37}, {'value': 37}),
|
||||||
|
([37, True], [37, True]),
|
||||||
|
((37, False), [37, False]),
|
||||||
|
)
|
||||||
for method in methods:
|
for method in methods:
|
||||||
with self.subTest(method=method):
|
with self.subTest(method=method):
|
||||||
client_method = getattr(self.client, method)
|
for data, expected in tests:
|
||||||
method_name = method.upper()
|
with self.subTest(data):
|
||||||
response = client_method('/json_view/', {'value': 37}, content_type='application/json')
|
client_method = getattr(self.client, method)
|
||||||
self.assertEqual(response.status_code, 200)
|
method_name = method.upper()
|
||||||
self.assertEqual(response.context['data'], 37)
|
response = client_method('/json_view/', data, content_type='application/json')
|
||||||
self.assertContains(response, 'Viewing %s page.' % method_name)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.context['data'], expected)
|
||||||
|
self.assertContains(response, 'Viewing %s page.' % method_name)
|
||||||
|
|
||||||
def test_json_encoder_argument(self):
|
def test_json_encoder_argument(self):
|
||||||
"""The test Client accepts a json_encoder."""
|
"""The test Client accepts a json_encoder."""
|
||||||
|
|
|
@ -83,14 +83,14 @@ def post_view(request):
|
||||||
def json_view(request):
|
def json_view(request):
|
||||||
"""
|
"""
|
||||||
A view that expects a request with the header 'application/json' and JSON
|
A view that expects a request with the header 'application/json' and JSON
|
||||||
data with a key named 'value'.
|
data, which is deserialized and included in the context.
|
||||||
"""
|
"""
|
||||||
if request.META.get('CONTENT_TYPE') != 'application/json':
|
if request.META.get('CONTENT_TYPE') != 'application/json':
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
t = Template('Viewing {} page. With data {{ data }}.'.format(request.method))
|
t = Template('Viewing {} page. With data {{ data }}.'.format(request.method))
|
||||||
data = json.loads(request.body.decode('utf-8'))
|
data = json.loads(request.body.decode('utf-8'))
|
||||||
c = Context({'data': data['value']})
|
c = Context({'data': data})
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue