114

I want to serialize my queryset, and I want it in a format as this view outputs:

class JSONListView(ListView):
    queryset = Users.objects.all()

    def get(self, request, *args, **kwargs):
        return HttpResponse(json.dumps({'data': [['bar','foo','bar','foo'],['foo','bar','foo','bar']]}, indent=4), content_type='application/json')

I simply don't know how to output the queryset instead of the manual data in the example.

I've tried

json.dumps({"data": self.get_queryset()})

and

serializers.serialize("json", {'data': self.get_queryset()})

but it won't work. What am I doing wrong? Do I need to make a custom JSON Encoder?

funnydman
  • 9,083
  • 4
  • 40
  • 55
user2232982
  • 1,325
  • 2
  • 12
  • 16
  • What didn't work? Have you read [the docs on serialising querysets](https://docs.djangoproject.com/en/dev/topics/serialization/)? I'd imagine the problem is with ForeignKey/M2M relationships within your model – Timmy O'Mahony Apr 08 '13 at 08:16

8 Answers8

168

You can use JsonResponse with values. Simple example:

from django.http import JsonResponse

def some_view(request):
    data = list(SomeModel.objects.values())  # wrap in list(), because QuerySet is not JSON serializable
    return JsonResponse(data, safe=False)  # or JsonResponse({'data': data})
 

Or another approach with Django's built-in serializers:

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

def some_view(request):
    qs = SomeModel.objects.all()
    qs_json = serializers.serialize('json', qs)
    return HttpResponse(qs_json, content_type='application/json')

In this case result is slightly different (without indent by default):

[
    {
        "model": "some_app.some_model",
        "pk": 1,
        "fields": {
            "name": "Elon",
            "age": 48,
            ...
        }
    },
    ...
]

I have to say, it is good practice to use something like marshmallow to serialize queryset.

...and a few notes for better performance:

  • use pagination if your queryset is big;
  • use objects.values() to specify list of required fields to avoid serialization and sending to client unnecessary model's fields (you also can pass fields to serializers.serialize);
Mark Mishyn
  • 3,921
  • 2
  • 28
  • 30
  • Using `JsonResponse` with JSON is incorrect, `HttpResponse` should be used instead. If using – Alex78191 Oct 28 '17 at 19:20
  • 2
    i don't like Django model format with specific fileds `{model: "name.sub", pk: 1, fields: {,…}}`. I like [simple JSON with it's own fields](https://stackoverflow.com/a/30243413/4854931). – Alex78191 Oct 28 '17 at 19:59
  • @Alex78191 thank you, you are right. I expected that Django's serializers work in the same way as DRF serializers. – Mark Mishyn Oct 29 '17 at 06:49
  • 5
    sorry for the rand, but this is so much complication for returning very basic data – vladimir.gorea Feb 28 '19 at 04:08
  • @vladimir.gorea there are only 3-4 lines of code + imports in every example. – Mark Mishyn Feb 28 '19 at 09:36
  • @MarkMishyn I was referring to the Django serializers. I just want some variable with simple json-ized data. Probably a look to serialize yourself is easier. – vladimir.gorea Mar 01 '19 at 01:32
  • Option#1 of Mark Mishyn's answer is the best option when using DRF. – AwsAnurag Oct 31 '20 at 10:50
  • @AwsAnurag, DRF has it's own serializers and Response class, so you don't need use Django's Json Response or values_list. – Mark Mishyn Nov 01 '20 at 05:23
  • 1
    @Mark - Thanks yes but there are certain limitations when using custom User model where your first option is a quicker approach to return a GET response without violating Django rules. This is of course my personal preference and I am sure there are better ways out there. I up-voted your answer because I am sure this will help others who are not aware of such better ways. Thank again. :-) – AwsAnurag Nov 01 '20 at 06:08
  • What is `SomeModel`? – Brian Wiley May 17 '21 at 02:57
  • @BrianWiley it's a instance of django.db.Model – Mark Mishyn May 17 '21 at 07:00
43

It didn't work, because QuerySets are not JSON serializable.

1) In case of json.dumps you have to explicitely convert your QuerySet to JSON serializable objects:

class Model(model.Model):
    def as_dict(self):
        return {
            "id": self.id,
            # other stuff
        }

And the serialization:

dictionaries = [ obj.as_dict() for obj in self.get_queryset() ]
return HttpResponse(json.dumps({"data": dictionaries}), content_type='application/json')

2) In case of serializers. Serializers accept either JSON serializable object or QuerySet, but a dictionary containing a QuerySet is neither. Try this:

serializers.serialize("json", self.get_queryset())

Read more about it here:

https://docs.djangoproject.com/en/dev/topics/serialization/

Eineki
  • 14,773
  • 6
  • 50
  • 59
freakish
  • 54,167
  • 9
  • 132
  • 169
  • That's a good answer. I will go with the first solution. In your second solution, how is it possible to assign a 'key' to the data? Should it be something like {"data": serializers.serialize("json", self.get_queryset())}? – user2232982 Apr 08 '13 at 09:35
  • 1
    @user2232982 I'm not sure to be honest, I'm always using first technique. :) Your solution is not good, because you get a dictionary with a JSON string so you still need to serialize it resulting in double serialized object. :O – freakish Apr 08 '13 at 09:37
  • The first tehnique is an invention of the wheel. – Alex78191 Oct 28 '17 at 19:50
24

For a efficient solution, you can use .values() function to get a list of dict objects and then dump it to json response by using i.e. JsonResponse (remember to set safe=False).

Once you have your desired queryset object, transform it to JSON response like this:

...
data = list(queryset.values())
return JsonResponse(data, safe=False)

You can specify field names in .values() function in order to return only wanted fields (the example above will return all model fields in json objects).

serfer2
  • 2,573
  • 1
  • 23
  • 17
9

To return the queryset you retrieved with queryset = Users.objects.all(), you first need to serialize them.

Serialization is the process of converting one data structure to another. Using Class-Based Views, you could return JSON like this.

from django.core.serializers import serialize
from django.http import JsonResponse
from django.views.generic import View

class JSONListView(View):
    def get(self, request, *args, **kwargs):
        qs = User.objects.all()
        data = serialize("json", qs)
        return JsonResponse(data)

This will output a list of JSON. For more detail on how this works, check out my blog article How to return a JSON Response with Django. It goes into more detail on how you would go about this.

Royalbishop101
  • 179
  • 2
  • 9
  • i don't believe this outputs a JSON string. I believe you end up with a bytes object, so this is not a very useful solution unless you mean to only send JSON back to the client. – Jamie Marshall Feb 19 '21 at 17:08
5

If the goal is to build an API that allow you to access your models in JSON format I recommend you to use the django-restframework that is an enormously popular package within the Django community to achieve this type of tasks.

It include useful features such as Pagination, Defining Serializers, Nested models/relations and more. Even if you only want to do minor Javascript tasks and Ajax calls I would still suggest you to build a proper API using the Django Rest Framework instead of manually defining the JSON response.

Community
  • 1
  • 1
Marcus Lind
  • 10,374
  • 7
  • 58
  • 112
1

Another way to turn queryset into JSON, is appending necessary elements to an empty list with loop. It provides to design customizable JSON.

queryset = Users.objects.all()
output = []
for query in queryset:
   output.append('id': query.id, 'name': query.name, etc...)
return JSONResponse(output, safe=False) 
nogabemist
  • 402
  • 5
  • 29
-1

Try this:

class JSONListView(ListView):
    queryset = Users.objects.all()


    def get(self, request, *args, **kwargs):
        data = {}
        data["users"] = get_json_list(queryset)
        return JSONResponse(data)


def get_json_list(query_set):
    list_objects = []
    for obj in query_set:
        dict_obj = {}
        for field in obj._meta.get_fields():
            try:
                if field.many_to_many:
                    dict_obj[field.name] = get_json_list(getattr(obj, field.name).all())
                    continue
                dict_obj[field.name] = getattr(obj, field.name)
            except AttributeError:
                continue
        list_objects.append(dict_obj)
    return list_objects
k15
  • 15
  • 1
  • 1
    Giving code out and doing others job for them, without explaining the original problem and the solution used, doesn't help much... – matteeyah Aug 18 '16 at 21:28
-3
from django.http import JsonResponse

def SomeFunction():
       dict1 = {}

       obj = list( Mymodel.objects.values() )

       dict1['data']=obj

return JsonResponse(dict1)

Try this code for Django

sur.la.route
  • 440
  • 3
  • 11