Use this decorator on a function that returns a dict to get a JSON view, with error handling.
Features:
- response always includes a 'result' attribute ('ok' by default)
- catches all errors and mails the admins
- always returns JSON even on errors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | from django.http import HttpResponse
from django.utils import simplejson
from django.core.mail import mail_admins
from django.utils.translation import ugettext as _
import sys
def json_view(func):
def wrap(request, *a, **kw):
response = None
try:
response = func(request, *a, **kw)
assert isinstance(response, dict)
if 'result' not in response:
response['result'] = 'ok'
except KeyboardInterrupt:
# Allow keyboard interrupts through for debugging.
raise
except Exception, e:
# Mail the admins with the error
exc_info = sys.exc_info()
subject = 'JSON view error: %s' % request.path
try:
request_repr = repr(request)
except:
request_repr = 'Request repr() unavailable'
import traceback
message = 'Traceback:\n%s\n\nRequest:\n%s' % (
'\n'.join(traceback.format_exception(*exc_info)),
request_repr,
)
mail_admins(subject, message, fail_silently=True)
# Come what may, we're returning JSON.
if hasattr(e, 'message'):
msg = e.message
else:
msg = _('Internal error')+': '+str(e)
response = {'result': 'error',
'text': msg}
json = simplejson.dumps(response)
return HttpResponse(json, mimetype='application/json')
return wrap
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
This is really useful, but there's one subtle bug. The dict returned from the wrapped function is altered by the wrapper. If the value happens to be something persistent in your application, odd and unexpected things will happen. We have an ajax method to send config data to the client, data that is used elsewhere in the application. I was seeing occasional errors about "result", and couldn't figure it out. I finally tracked it down to this wrapper.
The lines:
Should be changed to:
Or you can ditch the assert, and go with:
#
Very nice! Thanks for this one.
#
Can I get an example of how to use this? I saved it as 'json_view.py' within my app files, then used 'from project.app.json_view import json_view' at views.py and add '@json_view' at a view function I want to see in JSON, but browser react as a download and the file is a text file with the JSON inside. Is this ok? Can a javascript interact with a downloadable JSON?
#
This has a problem with decimals. As of simplejson 2.1.0, you can use use_decimal=True. So switch this:
To this:
#
Please login first before commenting.