How to output Django queryset as JSON?
Asked Answered
R

10

115

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?

Richardo answered 8/4, 2013 at 8:10 Comment(1)
What didn't work? Have you read the docs on serialising querysets? I'd imagine the problem is with ForeignKey/M2M relationships within your modelAshla
A
173

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);
Arnuad answered 15/6, 2016 at 15:7 Comment(11)
Using JsonResponse with JSON is incorrect, HttpResponse should be used instead. If usingTransept
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.Transept
@Transept thank you, you are right. I expected that Django's serializers work in the same way as DRF serializers.Arnuad
sorry for the rand, but this is so much complication for returning very basic dataCabman
@Cabman there are only 3-4 lines of code + imports in every example.Arnuad
@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.Cabman
Option#1 of Mark Mishyn's answer is the best option when using DRF.Circumrotate
@AwsAnurag, DRF has it's own serializers and Response class, so you don't need use Django's Json Response or values_list.Arnuad
@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. :-)Circumrotate
What is SomeModel?Moniquemonism
@BrianWiley it's a instance of django.db.ModelArnuad
D
44

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/

Dobsonfly answered 8/4, 2013 at 8:27 Comment(3)
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())}?Richardo
@Richardo 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. :ODobsonfly
The first tehnique is an invention of the wheel.Transept
O
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).

Obsessive answered 31/12, 2018 at 11:31 Comment(0)
N
10

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.

Nephogram answered 16/10, 2020 at 19:24 Comment(1)
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.Gnathous
G
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.

Gravure answered 16/11, 2017 at 3:32 Comment(0)
L
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) 
Limiting answered 22/10, 2021 at 8:57 Comment(0)
I
0

Extending serializers.Serializer is the way to go really however for some reason if you really don't want to then the following should give you some json from query set.

from django.core import serializers
from rest_framework.response import Response
    
peoples = People.objects.all()
data = serializers.serialize('json', peoples)
json_data = json.loads(data)
return Response(json_data) 
Interminable answered 4/3 at 7:30 Comment(0)
P
0

Based on some responses, I ended up creating a template filter:

# your-app/templatetags/your-file.py
from django.core import serializers

@register.filter
def json(data):
    return serializers.serialize('json', data)

The template filter accepts a queryset. You could just pass YourModel.objects.all()

{# your-app/templates/your-app/your-template.html #}
<script>
    let data = {{ rows|json|safe }}
</script>
Perspiration answered 25/3 at 14:29 Comment(0)
U
-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
Unblown answered 18/8, 2016 at 21:7 Comment(1)
Giving code out and doing others job for them, without explaining the original problem and the solution used, doesn't help much...Anodize
R
-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

Roadstead answered 3/12, 2020 at 4:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.