Package: django-jsonview
django-jsonviewis a simple decorator that translates Python objects
to JSON and makes sure your view will always return JSON.I’ve copied and pasted this so often I decided I just wanted to put it
in a package.InstallationJust install withpip:pip install django-jsonviewNo need to add toINSTALLED_APPSor anything.UsageJust import the decorator, use, and return a JSON-serializable object:from jsonview.decorators import json_view

@json_view
def my_view(request):
    return {
        'foo': 'bar',
    }Class-based views(CBVs) can inherit from JsonView, use Django’s@method_decoratoror wrap the output of.as_view():# inherit from JsonView
from jsonview.views import JsonView


class MyView(JsonView):
    def get_context_data(self, **kwargs):
        context = super(MyView, self).get_context_data(**kwargs)
        context['my_key'] = 'some value'
        return context

# or, method decorator
from django.utils.decorators import method_decorator
from jsonview.decorators import json_view


class MyView(View):
    @method_decorator(json_view)
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)

# or, in URLconf

patterns = [
    url(r'^/my-view/$', json_view(MyView.as_view())),
]Content TypesIf you need to return a content type other than the standardapplication/json, you can specify that in the decorator with thecontent_typeargument, for example:from jsonview.decorators import json_view

@json_view(content_type='application/vnd.github+json')
def myview(request):
    return {'foo': 'bar'}The response will have the appropriate content type header.Return ValuesThe default case is to serialize your return value and respond with HTTP
200 and a Content-Type ofapplication/json.The@json_viewdecorator will handle many exceptions and other
cases, including:Http404PermissionDeniedHttpResponseNotAllowed(e.g.require_GET,require_POST)jsonview.exceptions.BadRequest(see below)Any other exception (logged todjango.request).Any of these exceptions will return the correct status code (i.e., 404,
403, 405, 400, 500) a Content-Type ofapplication/json, and a
response body that looks like:json.dumps({
    'error': STATUS_CODE,
    'message': str(exception),
})NoteAs of v0.4, application exceptions donotbehave this way ifDEBUG = False. WhenDEBUG = False, themessagevalue is
alwaysAn error occurred. WhenDEBUG = True, the exception
message is sent back.BadRequestHTTP does not have a great status code for “you submitted a form that
didn’t validate,” and so Django doesn’t support it very well. Most
examples just return 200 OK.Normally, this is fine. But if you’re submitting a form via Ajax, it’s
nice to have a distinct status for “OK” and “Nope.” The HTTP 400 Bad
Request response is the fallback for issues with a request
not-otherwise-specified, so let’s do that.To cause@json_viewto return a 400, just raise ajsonview.exceptions.BadRequestwith whatever appropriate error
message.ExceptionsIf your view raises an exception,@json_viewwill catch the
exception, log it to the normaldjango.requestlogger, and return a
JSON response with a status of 500 and a body that looks like the
exceptions in theReturn Valuessection.NoteBecause the@json_viewdecorator handles the exception instead of
propagating it, any exception middleware willnotbe called, and
any response middlewarewillbe called.Status CodesIf you need to return a different HTTP status code, just return two
values instead of one. The first is your serializable object, the second
is the integer status code:@json_view
def myview(request):
    if not request.user.is_subscribed():
        # Send a 402 Payment Required status.
        return {'subscribed': False}, 402
    # Send a 200 OK.
    return {'subscribed': True}Extra HeadersYou can add custom headers to the response by returning a tuple of three
values: an object, a status code, and a dictionary of headers.@json_view
def myview(request):
    return {}, 200, {'X-Server': 'myserver'}Custom header values may be overwritten by response middleware.Raw Return ValuesTo make it possible to cache JSON responses as strings (and because they
aren’t JSON serializable anyway) if you return anHttpResponseobject (or subclass) it will be passed through unchanged, e.g.:from django import http
from jsonview.decorators import JSON

@json_view
def caching_view(request):
    kached = cache.get('cache-key')
    if kached:
        return http.HttpResponse(kached, content_type=JSON)
    # Assuming something else populates this cache.
    return {'complicated': 'object'}Note@require_POSTand the other HTTP method decorators  work byreturninga response, rather thanraising, an exception, soHttpResponseNotAllowedis handled specially.Alternative JSON ImplementationsThere is a healthy collection of JSON parsing and generating libraries
out there. By default, it will use the old standby, the stdlibjsonmodule. But, if you’d rather useujson, orcjsonoryajl, you should
go for it. Just add this to your Django settings:JSON_MODULE = 'ujson'Anything, as long as it’s a module that has.loads()and.dumps()methods.Configuring JSON OutputAdditional keyword arguments can be passed tojson.dumps()via theJSON_OPTIONS = {}Django setting. For example, to pretty-print JSON
output:JSON_OPTIONS = {
    'indent': 4,
}Or to compactify it:JSON_OPTIONS = {
    'separators': (',', ':'),
}jsonview usesDjangoJSONEncoderby default. To use a different JSON
encoder, use theclsoption:JSON_OPTIONS = {
    'cls': 'path.to.MyJSONEncoder',
}JSON_OPTIONS['cls']may be a dotted string or aJSONEncoderclass.If you are using a JSON module that does not support the ``cls``
kwarg, such as ujson, set theclsoption toNone:JSON_OPTIONS = {
    'cls': None,
}Default value of content-type is ‘application/json’. You can change it
via theJSON_DEFAULT_CONTENT_TYPEDjango settings. For example, to
add charset:JSON_DEFAULT_CONTENT_TYPE = 'application/json; charset=utf-8'Atomic RequestsBecause@json_viewcatches exceptions, the normal Django settingATOMIC_REQUESTSdoes not correctly cause a rollback. This can be
worked around by explicitly setting@transaction.atomicbelowthe@json_viewdecorator, e.g.:@json_view
@transaction.atomic
def my_func(request):
    # ...ContributingPull requestsandissueswelcome! I ask two simple things:Tests, including the new ones you added, must pass. (See below.)Coverage should not drop below 100. You can installcoveragewith
pip and run./run.sh coverageto check.Theflake8tool should not return any issues.Running TestsTo run the tests, you probably want to create avirtualenv, then
install Django and Mock withpip:pip install Django==${DJANGO_VERSION} mock==1.0.1Then run the tests with:./run.sh test