10

I'm working in Django 1.8 and having trouble finding the modern way to do this.

This is what I've got, based on Googling and this blog post:

results = PCT.objects.filter(code__startswith='a')
json_res = []
for result in results:
    json_res.append(result.as_dict())
return HttpResponse(json.dumps(json_res), content_type='application/json')

However this gives me 'PCT' object has no attribute 'as_dict'.

Surely there must be a neater way by now?

I was wondering if it was possible to use JSONResponse but frustratingly, the docs give no example of how to use JSONRespose with a queryset, which must be the most common use case. I have tried this:

results = PCT.objects.filter(code__startswith='a')
return JsonResponse(results, safe=False)

This gives [<PCT: PCT object>, <PCT: PCT object>] is not JSON serializable.

isherwood
  • 58,414
  • 16
  • 114
  • 157
Richard
  • 62,943
  • 126
  • 334
  • 542
  • possible duplicate of [Creating a JSON response using Django and Python](http://stackoverflow.com/questions/2428092/creating-a-json-response-using-django-and-python) – John Schmitt May 14 '15 at 17:08
  • but *surely* things must have got simpler since 2010? – Richard May 14 '15 at 17:09
  • They surely have, and it's referenced in the first answer to the duplicate question. – John Schmitt May 14 '15 at 17:10
  • ok, so that links to here: http://stackoverflow.com/questions/2428092/creating-a-json-response-using-django-and-python/24411716#24411716 which shows how to return a dictionary using JSONResponse. But I have a QuerySet, not a dictionary. I'm trying `return JsonResponse(results.values(), safe=False)` but that gives me a `TypeError: not JSON serializable`. Any ideas? – Richard May 14 '15 at 17:14
  • I'm really not trying to be difficult, but this does seem like one of the most common things one might want to do in Django, given the move to front-end apps: I'm surprised it's so difficult to figure out how to do it. – Richard May 14 '15 at 17:15
  • If all you want to do is return the result of a model-query as part of a GET, then this sounds like a REST-compatible call. Did you have a look at the [REST-framework](http://www.django-rest-framework.org/)? – mknecht May 14 '15 at 17:22
  • @mknecht looks like I may have to use that if this is impossible, but seems a bit heavyweight - I just want a simple JSON method that I can use for an autocomplete field, not a full RESTful API. – Richard May 14 '15 at 17:25
  • I really don't think this question is a duplicate: the "duplicate" is ancient, and yes it has a recent update, but the update is about converting a dictionary to JSON, not a QuerySet, so that's quite different. – Richard May 14 '15 at 17:26
  • related: https://stackoverflow.com/q/26373992 – djvg Jan 19 '23 at 09:17

5 Answers5

32

Simplest solution without any additional framework:

results = PCT.objects.filter(code__startswith='a').values('id', 'name')
return JsonResponse({'results': list(results)})

returns {'results': [{'id': 1, 'name': 'foo'}, ...]}

or if you only need the values:

results = PCT.objects.filter(code__startswith='a').values_list('id', 'name')
return JsonResponse({'results': list(results)})

returns {'results': [[1, 'foo'], ...]}

Leistungsabfall
  • 6,368
  • 7
  • 33
  • 41
  • So close! But the first snippet gives me the following error message: `[{'code': u'5M1', 'name': u'South Birmingham'}, {'code': u'5M3', 'name': u'Walsall Teaching'}`] is not JSON serializable`. – Richard May 14 '15 at 17:20
  • 4
    This doesn't work for me :( I get a ` is not JSON serializable` with `return JsonResponse({'results': list(results)})` – cfraser Jul 13 '17 at 16:15
5

use values() to return a querydict, and pass that to json.dumps

values = PCT.objects.filter(code__startswith='a').values()
return HttpResponse(json.dumps(values), content_type='application/json')

https://docs.djangoproject.com/en/1.8/ref/models/querysets/#values

wobbily_col
  • 11,390
  • 12
  • 62
  • 86
  • 1
    Thansk, but same problem as with other answers: `TypeError... is not JSON serializable`. – Richard May 14 '15 at 17:24
  • strange, it should work. http://stackoverflow.com/questions/25798395/python-query-dict-to-json. Maybe try calling the dict() method on values. – wobbily_col May 14 '15 at 17:32
4

Most of these answers are out of date. Here's what I use:

views.py (returns HTML)

from django.shortcuts import render
from django.core import serializers

def your_view(request):
    data = serializers.serialize('json', YourModel.objects.all())
    context = {"data":data}
    return render(request, "your_view.html", context)

views.py (returns JSON)

from django.core import serializers
from django.http import HttpResponse

def your_view(request):
    data = serializers.serialize('json', YourModel.objects.all())
    return HttpResponse(data, content_type='application/json')
devdrc
  • 1,853
  • 16
  • 21
0

Take a look at Django's serialization framework. It allows not only the XML format, but also JSON and YAML.

Adrian Ghiuta
  • 1,569
  • 16
  • 29
  • Thanks, having read through that page I've got as far as `data = serializers.serialize("json", results)` and then `return data` but that gives me an error message about Unicode. Is there a missing step? – Richard May 14 '15 at 17:20
0

The accepted answer, using JsonResponse, is nice and simple. However, it does not return complete objects.

An alternative is to use Django's serializers. Here's an example copied verbatim from the admin actions documentation:

...
   response = HttpResponse(content_type="application/json")
   serializers.serialize("json", queryset, stream=response)
   return response

This is very similar to what happens in Django's JsonResponse, as can be seen in the source.

The main difference is that JsonResponse calls json.dumps() directly, and does not know how to handle querysets, whereas the example above uses serializers.serialize('json', ...), which does know how to handle querysets, and returns complete objects that can also be de-serialized later on.

If you want to save directly to file (using content-disposition: attachment to open a save dialog in the browser), you could use a FileResponse, for example:

...
    data = serializers.serialize('json', queryset)
    return FileResponse(
        io.BytesIO(data.encode('utf-8')),
        content_type='application/json',
        as_attachment=True,
        filename=f'{queryset.model.__name__.lower()}-objects.json'
    )
djvg
  • 11,722
  • 5
  • 72
  • 103