如何输出 Django 查询集为 JSON?

我想序列化我的查询集,我希望它以这个视图输出的格式:

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')

我只是不知道如何输出查询集而不是示例中的手动数据。

我试过了

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

还有

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

但它不会工作。我做错了什么? 我需要自定义 JSON 编码器吗?

161303 次浏览

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/

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);

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

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.

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).

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.

from django.http import JsonResponse


def SomeFunction():
dict1 = {}


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


dict1['data']=obj


return JsonResponse(dict1)

Try this code for Django

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)