Выходной набор запросов 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?


person user2232982    schedule 08.04.2013    source источник
comment
Что не сработало? Вы читали документацию по сериализации наборов запросов? Я предполагаю, что проблема связана с отношениями ForeignKey/M2M в вашей модели.   -  person Timmy O'Mahony    schedule 08.04.2013


Ответы (7)


Вы можете использовать JsonResponse с values. Простой пример:

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

Или другой подход с использованием встроенных сериализаторов Django:

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": "Elon",
            "age": 48,
            ...
        }
    },
    ...
]

Я должен сказать, что для сериализации набора запросов рекомендуется использовать что-то вроде marshmallow.

... и несколько замечаний для лучшей производительности:

  • используйте разбиение на страницы, если ваш набор запросов большой;
  • используйте objects.values(), чтобы указать список обязательных полей, чтобы избежать сериализации и отправки клиенту ненужных полей модели (вы также можете передать fields в serializers.serialize);
person Mark Mishyn    schedule 15.06.2016
comment
Использование JsonResponse с JSON неверно, вместо этого следует использовать HttpResponse. При использовании - person Alex78191; 28.10.2017
comment
мне не нравится формат модели Django с определенными файлами {model: "name.sub", pk: 1, fields: {,…}}. Мне нравится простой JSON со своими полями. - person Alex78191; 28.10.2017
comment
@ Alex78191 спасибо, ты прав. Я ожидал, что сериализаторы Django работают так же, как сериализаторы DRF. - person Mark Mishyn; 29.10.2017
comment
извините за ранд, но это так сложно для возврата очень простых данных - person vladimir.gorea; 28.02.2019
comment
@vladimir.gorea в каждом примере всего 3-4 строки кода + импорт. - person Mark Mishyn; 28.02.2019
comment
@MarkMishyn Я имел в виду сериализаторы Django. Мне просто нужна переменная с простыми данными в формате json. Наверное, проще сериализовать себя. - person vladimir.gorea; 01.03.2019
comment
Вариант № 1 ответа Марка Мишина - лучший вариант при использовании DRF. - person AwsAnurag; 31.10.2020
comment
@AwsAnurag, DRF имеет свои собственные сериализаторы и класс Response, поэтому вам не нужно использовать Json Response или values_list от Django. - person Mark Mishyn; 01.11.2020
comment
@Mark - Спасибо, да, но существуют определенные ограничения при использовании пользовательской модели пользователя, где ваш первый вариант — это более быстрый подход к возврату ответа GET без нарушения правил Django. Это, конечно, мое личное предпочтение, и я уверен, что есть лучшие способы. Я проголосовал за ваш ответ, потому что уверен, что это поможет другим, кто не знает о таких лучших способах. Еще раз спасибо. :-) - person AwsAnurag; 01.11.2020
comment
Что такое SomeModel? - person Brian Wiley; 17.05.2021
comment
@BrianWiley это экземпляр django.db.Model - person Mark Mishyn; 17.05.2021

Это не сработало, потому что QuerySet не сериализуем 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/

person freakish    schedule 08.04.2013
comment
Это хороший ответ. Я пойду с первым решением. В вашем втором решении, как можно назначить «ключ» данным? Должно ли это быть что-то вроде {data: serializers.serialize(json, self.get_queryset())}? - person user2232982; 08.04.2013
comment
@user2232982 user2232982 Честно говоря, я не уверен, я всегда использую первую технику. :) Ваше решение не очень хорошее, потому что вы получаете словарь со строкой JSON, поэтому вам все равно нужно его сериализовать, что приводит к двойному сериализованному объекту. :О - person freakish; 08.04.2013
comment
Первая техника — это изобретение колеса. - person Alex78191; 28.10.2017

Для эффективного решения вы можете использовать .values(). функция, чтобы получить список объектов dict, а затем выгрузить его в ответ json, используя, например, JsonResponse (не забудьте установить safe=False).

Получив желаемый объект набора запросов, преобразуйте его в ответ JSON следующим образом:

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

Вы можете указать имена полей в функции .values(), чтобы возвращать только нужные поля (приведенный выше пример вернет все поля модели в объектах json).

person serfer2    schedule 31.12.2018

Чтобы вернуть набор запросов, который вы получили с помощью queryset = Users.objects.all(),, вам сначала нужно их сериализовать.

Сериализация — это процесс преобразования одной структуры данных в другую. Используя представления на основе классов, вы можете вернуть JSON следующим образом.

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)

Это выведет список JSON. Для получения более подробной информации о том, как это работает, ознакомьтесь со статьей в моем блоге Как чтобы вернуть ответ JSON с Django. Там более подробно рассказывается о том, как вы это сделаете.

person Royalbishop101    schedule 16.10.2020
comment
я не верю, что это выводит строку JSON. Я считаю, что вы получите объект bytes, так что это не очень полезное решение, если только вы не хотите отправлять JSON обратно клиенту. - person Jamie Marshall; 19.02.2021

Если цель состоит в том, чтобы создать API, который позволит вам получить доступ к вашим моделям в формате JSON, я рекомендую вам использовать django-restframework, который является чрезвычайно популярным пакетом в сообществе Django для решения задач такого типа.

Он включает в себя полезные функции, такие как разбиение на страницы, определение сериализаторов, вложенные модели/отношения и многое другое. Даже если вы хотите выполнять только второстепенные задачи Javascript и вызовы Ajax, я бы все же посоветовал вам создать правильный API с использованием Django Rest Framework вместо того, чтобы вручную определять ответ JSON.

person Marcus Lind    schedule 16.11.2017

Попробуй это:

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
person k15    schedule 18.08.2016
comment
Предоставление кода и выполнение работы за других без объяснения исходной проблемы и используемого решения мало помогает... - person matteeyah; 19.08.2016

from django.http import JsonResponse

def SomeFunction():
       dict1 = {}

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

       dict1['data']=obj

return JsonResponse(dict1)

Попробуйте этот код для Django

person Sujith suji    schedule 03.12.2020