Вывод 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 Encoder?
Ответы
Ответ 1
Это не сработало, потому что QuerySets не являются сериализуемыми JSON.
1) В случае json.dumps
вам необходимо явно преобразовать ваш QuerySet в сериализуемые объекты JSON:
class Model(model.Model):
def as_dict(self):
return {
"id": self.id,
# other stuff
}
И сериализация:
dictionaries = [ obj.as_dict() for obj in self.get_queryset() ]
return HttpResponse(json.dumps({"data": dictionaries}), content_type='application/json')
2) В случае сериализаторов. Сериализаторы принимают либо сериализуемый объект JSON, либо QuerySet, но словарь, содержащий QuerySet, не является ни тем, ни другим. Попробуйте следующее:
serializers.serialize("json", self.get_queryset())
Подробнее об этом читайте здесь:
https://docs.djangoproject.com/en/dev/topics/serialization/
Ответ 2
Простой пример:
from django.http import JsonResponse
def some_view(request):
data = list(SomeModel.objects.values())
return JsonResponse(data, safe=False) # or JsonResponse({'data': data})
Или другой подход:
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')
В этом случае ответ будет бит другим (без отступа по умолчанию):
[
{
"model": "some_app.some_model",
"pk": 1,
"fields": {
"name": "Ivan",
"age": 35,
...
}
},
...
]
Я должен сказать, что хорошая практика использовать что-то вроде marshmallow для сериализации объектов.
И есть несколько заметок, как сделать ваше представление как можно быстрее для лучшей производительности:
- используйте разбиение на страницы, если ваш запрос очень большой;
- используйте
objects.values()
, чтобы указать список обязательных полей, чтобы избежать сериализации и отправки ненужным полям модели клиента (вы также можете передать fields
в serializers.serialize
);
- установите подходящий
settings.CONN_MAX_AGE
, например 500 (значение из документации heroku);
- вы можете использовать функцию, основанную на представлении, для лучшей производительности (но четкий код, очевидно, лучше, чем чуть более быстрый код, будьте осторожны);
Ответ 3
Попробуйте следующее:
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
Ответ 4
Если целью является создание API, который позволит вам получить доступ к вашим моделям в формате JSON, я рекомендую вам использовать django-restframework
, который является чрезвычайно популярным пакетом в сообществе Django для достижения таких задач.
Он включает полезные функции, такие как разбиение на страницы, определение сериализаторов, вложенные модели/отношения и многое другое. Даже если вы хотите выполнять незначительные задачи Javascript и Ajax-вызовы, я бы по-прежнему предлагал вам создать правильный API с помощью Django Rest Framework вместо того, чтобы вручную определять ответ JSON.