• Stars
    star
    247
  • Rank 163,127 (Top 4 %)
  • Language
    Python
  • License
    Other
  • Created over 11 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Return Python objects, always get JSON.

django-jsonview

django-jsonview is a simple decorator that translates Python objects to JSON and makes sure your view will always return JSON.

https://github.com/jsocol/django-jsonview/workflows/test/badge.svg?branch=main

Installation

Just install with pip:

pip install django-jsonview

No need to add to INSTALLED_APPS or anything.

Usage

Just 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_decorator or 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 Types

If you need to return a content type other than the standard application/json, you can specify that in the decorator with the content_type argument, 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 Values

The default case is to serialize your return value and respond with HTTP 200 and a Content-Type of application/json.

The @json_view decorator will handle many exceptions and other cases, including:

  • Http404
  • PermissionDenied
  • HttpResponseNotAllowed (e.g. require_GET, require_POST)
  • jsonview.exceptions.BadRequest (see below)
  • Any other exception (logged to django.request).

Any of these exceptions will return the correct status code (i.e., 404, 403, 405, 400, 500) a Content-Type of application/json, and a response body that looks like

json.dumps({
    'error': STATUS_CODE,
    'message': str(exception),
})

Note

As of v0.4, application exceptions do not behave this way if DEBUG = False. When DEBUG = False, the message value is always An error occurred. When DEBUG = True, the exception message is sent back.

BadRequest

HTTP 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_view to return a 400, just raise a jsonview.exceptions.BadRequest with whatever appropriate error message.

Exceptions

If your view raises an exception, @json_view will catch the exception, log it to the normal django.request logger, and return a JSON response with a status of 500 and a body that looks like the exceptions in the Return Values section.

Note

Because the @json_view decorator handles the exception instead of propagating it, any exception middleware will not be called, and any response middleware will be called.

Status Codes

If 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 Headers

You 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 Values

To make it possible to cache JSON responses as strings (and because they aren't JSON serializable anyway) if you return an HttpResponse object (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_POST and the other HTTP method decorators work by returning a response, rather than raising, an exception, so HttpResponseNotAllowed is handled specially.

Alternative JSON Implementations

There is a healthy collection of JSON parsing and generating libraries out there. By default, it will use the old standby, the stdlib json module. But, if you'd rather use ujson, or cjson or yajl, 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 Output

Additional keyword arguments can be passed to json.dumps() via the JSON_OPTIONS = {} Django setting. For example, to pretty-print JSON output

JSON_OPTIONS = {
    'indent': 4,
}

Or to compactify it

JSON_OPTIONS = {
    'separators': (',', ':'),
}

jsonview uses DjangoJSONEncoder by default. To use a different JSON encoder, use the cls option

JSON_OPTIONS = {
    'cls': 'path.to.MyJSONEncoder',
}

JSON_OPTIONS['cls'] may be a dotted string or a JSONEncoder class.

If you are using a JSON module that does not support the ``cls`` kwarg, such as ujson, set the cls option to None

JSON_OPTIONS = {
    'cls': None,
}

Default value of content-type is 'application/json'. You can change it via the JSON_DEFAULT_CONTENT_TYPE Django settings. For example, to add charset

JSON_DEFAULT_CONTENT_TYPE = 'application/json; charset=utf-8'

Atomic Requests

Because @json_view catches exceptions, the normal Django setting ATOMIC_REQUESTS does not correctly cause a rollback. This can be worked around by explicitly setting @transaction.atomic below the @json_view decorator, e.g.

@json_view
@transaction.atomic
def my_func(request):
    # ...

Contributing

Pull requests and issues welcome! I ask two simple things:

  • Tests, including the new ones you added, must pass. (See below.)
  • Coverage should not drop below 100. You can install coverage with pip and run ./run.sh coverage to check.
  • The flake8 tool should not return any issues.

Running Tests

To run the tests, you probably want to create a virtualenv, then install Django and Mock with pip:

pip install Django==${DJANGO_VERSION} mock==1.0.1

Then run the tests with:

./run.sh test

More Repositories

1

django-ratelimit

Cache-based rate-limiting for Django
Python
1,046
star
2

django-adminplus

Easily add custom views to the Django admin.
Python
586
star
3

pystatsd

A Python client for statsd
Python
539
star
4

jingo-minify

Concat and minify JS and CSS for Jinja2+Jingo+Django
Python
67
star
5

django-cronjobs

A simple cron-running management command for Django
Python
55
star
6

oocurl

An Object-Oriented interface to PHP's cURL functions
PHP
31
star
7

sphinxapi

The Python client for Sphinx Search
Python
23
star
8

html5loopz

FruityLoops/FL Studio in HTML and JS.
JavaScript
19
star
9

logbot

An IRC logging bot for Node.js.
JavaScript
17
star
10

bitly-api-php

PHP
16
star
11

asteroids

Asteroids clone in JavaScript and Canvas.
JavaScript
14
star
12

jig

Jenkins-IRC-Github integration bot/server with some fancier features.
JavaScript
10
star
13

django-authority

Fork of a fork (Dan Fairs') of Jezdez's project
Python
8
star
14

pygotham-cd

Links to Tools I Talked About
7
star
15

dotfiles

My .dotfiles!
Ruby
6
star
16

dirk

Django to IRC bridge
Python
5
star
17

django-fail

Make your app fail!
5
star
18

yodawg

Directed Acyclic Word Graph implementation in C.
C
5
star
19

concurrency

some annotated examples of web server concurrency in python
Python
4
star
20

talks

slides from talks i've given
HTML
3
star
21

indirect3d

The worst pure-software 3D engine ever!
TypeScript
3
star
22

github-shortcuts

Firefox add-on to add some basic keyboard navigation to Github.
JavaScript
3
star
23

areyoudying.com

HTML
2
star
24

laundromat

Python
2
star
25

phake

Rake + ActiveRecord::Migration in PHP - Don't use but maybe interesting
PHP
2
star
26

jsocol.github.io

My site.
HTML
2
star
27

django-headegg

Python
2
star
28

xkcdbot

xkcdbot
JavaScript
2
star
29

joshua

Globally Distributed, Resilient File Serving
Python
2
star
30

insert-ad-code

WordPress plugin for inserting ads into posts
PHP
1
star
31

maveric

An old MVC framework in PHP—strongly recommend not using
PHP
1
star
32

recipes

Hmm.
1
star
33

poincare

draw a triangle on the Poincaré disc
JavaScript
1
star
34

shutdown

Wraps Go graceful shutdown boilerplate
Go
1
star
35

moodboard

Build mood boards with drag 'n' drop.
JavaScript
1
star
36

better-search-widget

A better search widget for Wordpress
PHP
1
star
37

monster

JavaScript
1
star
38

django-mq

Python
1
star
39

weft

Python
1
star
40

nextup.info

[sunset] Your Meeting. On Schedule.
CSS
1
star
41

Jetpacks

A repo to store my Jetpacks
1
star
42

ezgz

Wordpress plugin that gzips output
PHP
1
star
43

whattimeisitthere.info

JavaScript
1
star
44

most-comments-widget

A Wordpress widget showing the posts with the most comments.
PHP
1
star