Commit 0242134d authored by Lukasz Balcerzak's avatar Lukasz Balcerzak Committed by Tim Graham
Browse files

Fixed #17942 -- Added a JsonResponse class to more easily create JSON encoded responses.

Thanks leahculver for the suggestion and Erik Romijn,
Simon Charette, and Marc Tamlyn for the reviews.
parent e3d0790b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ from django.http.response import (HttpResponse, StreamingHttpResponse,
    HttpResponseRedirect, HttpResponsePermanentRedirect,
    HttpResponseNotModified, HttpResponseBadRequest, HttpResponseForbidden,
    HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseGone,
    HttpResponseServerError, Http404, BadHeaderError)
    HttpResponseServerError, Http404, BadHeaderError, JsonResponse)
from django.http.utils import (fix_location_header,
    conditional_content_removal, fix_IE_for_attach, fix_IE_for_vary)

@@ -16,6 +16,6 @@ __all__ = [
    'HttpResponsePermanentRedirect', 'HttpResponseNotModified',
    'HttpResponseBadRequest', 'HttpResponseForbidden', 'HttpResponseNotFound',
    'HttpResponseNotAllowed', 'HttpResponseGone', 'HttpResponseServerError',
    'Http404', 'BadHeaderError', 'fix_location_header',
    'Http404', 'BadHeaderError', 'fix_location_header', 'JsonResponse',
    'conditional_content_removal', 'fix_IE_for_attach', 'fix_IE_for_vary',
]
+25 −1
Original line number Diff line number Diff line
from __future__ import unicode_literals

import datetime
import time
import json
import sys
import time
from email.header import Header
try:
    from urllib.parse import urlparse
@@ -13,6 +14,7 @@ from django.conf import settings
from django.core import signals
from django.core import signing
from django.core.exceptions import DisallowedRedirect
from django.core.serializers.json import DjangoJSONEncoder
from django.http.cookie import SimpleCookie
from django.utils import six, timezone
from django.utils.encoding import force_bytes, force_text, iri_to_uri
@@ -456,3 +458,25 @@ class HttpResponseServerError(HttpResponse):

class Http404(Exception):
    pass


class JsonResponse(HttpResponse):
    """
    An HTTP response class that consumes data to be serialized to JSON.

    :param data: Data to be dumped into json. By default only ``dict`` objects
      are allowed to be passed due to a security flaw before EcmaScript 5. See
      the ``safe`` parameter for more information.
    :param encoder: Should be an json encoder class. Defaults to
      ``django.core.serializers.json.DjangoJSONEncoder``.
    :param safe: Controls if only ``dict`` objects may be serialized. Defaults
      to ``True``.
    """

    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, **kwargs):
        if safe and not isinstance(data, dict):
            raise TypeError('In order to allow non-dict objects to be '
                'serialized set the safe parameter to False')
        kwargs.setdefault('content_type', 'application/json')
        data = json.dumps(data, cls=encoder)
        super(JsonResponse, self).__init__(content=data, **kwargs)
+69 −1
Original line number Diff line number Diff line
@@ -823,6 +823,74 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
    :class:`~django.template.response.SimpleTemplateResponse`, and the
    ``render`` method must itself return a valid response object.

JsonResponse objects
====================

.. versionadded:: 1.7

.. class:: JsonResponse

.. method:: JsonResponse.__init__(data, encoder=DjangoJSONEncoder, safe=True, **kwargs)

   An :class:`HttpResponse` subclass that helps to create a JSON-encoded
   response. It inherits most behavior from its superclass with a couple
   differences:

   Its default ``Content-Type`` header is set to ``application/json``.

   The first parameter, ``data``, should be a ``dict`` instance. If the ``safe``
   parameter is set to ``False`` (see below) it can be any JSON-serializable
   object.

   The ``encoder``, which defaults to
   ``django.core.serializers.json.DjangoJSONEncoder``, will be used to
   serialize the data. See :ref:`JSON serialization
   <serialization-formats-json>` for more details about this serializer.

   The ``safe`` boolean parameter defaults to ``True``. If it's set to ``False``,
   any object can be passed for serialization (otherwise only ``dict`` instances
   are allowed). If ``safe`` is ``True`` and a non-``dict`` object is passed as
   the first argument, a :exc:`~exceptions.TypeError` will be raised.

Usage
-----

Typical usage could look like::

    >>> from django.http import JsonResponse
    >>> response = JsonResponse({'foo': 'bar'})
    >>> response.content
    '{"foo": "bar"}'


Serializing non-dictionary objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In order to serialize objects other than ``dict`` you must set the ``safe``
parameter to ``False``::

    >>> response = JsonResponse([1, 2, 3], safe=False)

Without passing ``safe=False``, a :exc:`~exceptions.TypeError` will be raised.

.. warning::

    Before the `5th edition of EcmaScript
    <http://www.ecma-international.org/publications/standards/Ecma-262.htm>`_
    it was possible to poison the JavaScript ``Array`` constructor. For this
    reason, Django does not allow passing non-dict objects to the
    :class:`~django.http.JsonResponse` constructor by default.  However, most
    modern browsers implement EcmaScript 5 which removes this attack vector.
    Therefore it is possible to disable this security precaution.

Changing the default JSON encoder
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you need to use a differ JSON encoder class you can pass the ``encoder``
parameter to the constructor method::

    >>> response = JsonResponse(data, encoder=MyJSONEncoder)

.. _httpresponse-streaming:

StreamingHttpResponse objects
+6 −2
Original line number Diff line number Diff line
@@ -671,15 +671,19 @@ Templates
* The new :tfilter:`truncatechars_html` filter truncates a string to be no
  longer than the specified number of characters, taking HTML into account.

Requests
^^^^^^^^
Requests and Responses
^^^^^^^^^^^^^^^^^^^^^^

* The new :attr:`HttpRequest.scheme <django.http.HttpRequest.scheme>` attribute
  specifies the scheme of the request (``http`` or ``https`` normally).


* The shortcut :func:`redirect() <django.shortcuts.redirect>` now supports
  relative URLs.

* The new :class:`~django.http.JsonResponse` subclass of
  :class:`~django.http.HttpResponse` helps easily create JSON-encoded responses.

Tests
^^^^^

+2 −0
Original line number Diff line number Diff line
@@ -216,6 +216,8 @@ the auth.User model has such a relation to the auth.Permission model::

This example links the given user with the permission models with PKs 46 and 47.

.. _serialization-formats-json:

JSON
~~~~

Loading