Как вернуть JSON без использования шаблона в Django?

82

Это связано с этим вопросом: Django возвращает json и html в зависимости от клиентского python


У меня есть командная строка Python API для приложения Django. Когда я получаю доступ к приложению через API, оно должно возвращать JSON, а в браузере - HTML. Я могу использовать разные URL-адреса для доступа к разным версиям, но как визуализировать HTML-шаблон и JSON в views.py с помощью всего одного шаблона?

Для рендеринга HTML я бы использовал:

return render_to_response('sample/sample.html....')

Но как мне сделать то же самое для JSON, не добавляя шаблон JSON? ( content-typeдолжно быть application/jsonвместо text/html)

Что будет определять выходы JSON и HTML?

Итак, в моем views.py :

if something:
    return render_to_response('html_template',.....)
else:
    return HttpReponse(jsondata,mimetype='application/json')
Ниран
источник
@Marcin Вы в основном сказали ему: «Нет, не делай этого так», не показав ему пример правильного пути. Вот для чего, кажется, этот ...
Изката
@ Джимми, если это произошло, тебе не следовало так быстро принимать ответ Марсина на другой вопрос. Подождите хотя бы день, кто-то, вероятно, ответил бы чем-то вроде ответа Уку Лоскит
Изката
@Izkata: Я действительно сказал ему, какую библиотеку использовать. Этот вопрос, по-видимому, предназначен для того, чтобы кто-то другой написал для него код.
Marcin

Ответы:

134

Я думаю, что проблема запуталась в том, что вы хотите. Я предполагаю, что вы на самом деле не пытаетесь поместить HTML в ответ JSON, а скорее хотите альтернативно вернуть HTML или JSON.

Во-первых, вам нужно понять основную разницу между ними. HTML - это формат представления. Он больше касается того, как отображать данные, чем сами данные. JSON - наоборот. Это чистые данные - в основном представление JavaScript некоторого набора данных Python (в данном случае), который у вас есть. Он служит просто уровнем обмена, позволяя вам перемещать данные из одной области вашего приложения (представления) в другую область вашего приложения (ваш JavaScript), которые обычно не имеют доступа друг к другу.

Имея это в виду, вы не будете «отображать» JSON, и в нем не будут задействованы шаблоны. Вы просто конвертируете все данные, которые находятся в игре (скорее всего, в значительной степени то, что вы передаете в качестве контекста в свой шаблон) в JSON. Это можно сделать либо с помощью библиотеки JSON Django (simplejson), если это данные произвольной формы, либо с помощью ее инфраструктуры сериализации, если это набор запросов.

simplejson

from django.utils import simplejson

some_data_to_dump = {
   'some_var_1': 'foo',
   'some_var_2': 'bar',
}

data = simplejson.dumps(some_data_to_dump)

Сериализация

from django.core import serializers

foos = Foo.objects.all()

data = serializers.serialize('json', foos)

В любом случае вы затем передаете эти данные в ответ:

return HttpResponse(data, content_type='application/json')

[Edit] В Django 1.6 и ранее код для возврата ответа был

return HttpResponse(data, mimetype='application/json')

[EDIT]: simplejson был удален из django , вы можете использовать:

import json

json.dumps({"foo": "bar"})

Или вы можете использовать, django.core.serializersкак описано выше.

Крис Прэтт
источник
Спасибо за разъяснения. Как определить в своих представлениях, что запрос ответа поступает от API для json? См. Редактировать вопрос.
Neeran
1
Вы можете использовать request.is_ajax(). Но для этого необходимо установить HTTP_X_REQUESTED_WITHзаголовок. Большинство библиотек JavaScript делают это автоматически, но если вы используете какой-либо другой тип клиента, вам необходимо убедиться, что он также устанавливает его. В качестве альтернативы вы можете передать строку запроса, например, ?jsonс URL-адресом, а затем проверить request.GET.has_key('json'), что, вероятно, немного более надежно.
Крис Пратт,
18
Обратите внимание, что теперь simplejson считается устаревшим в Django 1.5 . import json ; json.dumps(data)Вместо этого используйте .
Йонатан
1
OP должен проверить заголовок согласования типа содержимого «Принять» в requestобъекте. См.: W3.org/Protocols/rfc2616/rfc2616-sec14.html (большой объем чтения, но для демонстрации можно использовать упрощенный образец кода, и было бы несложно написать негибкую систему, которая хотя бы занимаются двумя делами, которые они просят)
Мерлин Морган-Грэм
14
В моем случае (Django 1.7) это был content_type = 'application / json', а не mimetype
mimetype
8

В случае ответа JSON шаблон для отображения отсутствует. Шаблоны предназначены для создания HTML-ответов. JSON - это HTTP-ответ.

Однако у вас может быть HTML, который отображается из шаблона с вашим ответом JSON.

html = render_to_string("some.html", some_dictionary)
serialized_data = simplejson.dumps({"html": html})
return HttpResponse(serialized_data, mimetype="application/json")
Уку Лоскит
источник
Нужно ли мне сначала сериализовать объекты?
Neeran
simplejson.dumps () - это то, что делает сериализацию.
Уку Лоскит,
спасибо, все работает нормально. мы также можем использовать json вместо simplejson @UkuLoskit
Чираг Канзария
7

Похоже, что структура Django REST использует заголовок принятия HTTP в запросе, чтобы автоматически определять, какой рендерер использовать:

http://www.django-rest-framework.org/api-guide/renderers/

Использование заголовка принятия HTTP может предоставить альтернативный источник для вашего «если что-то».

Чарльз Брандт
источник
7

Для рендеринга моих моделей в JSON в django 1.9 мне пришлось сделать следующее в моем views.py:

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

def index(request):
    objs = Mymodel.objects.all()
    jsondata = serializers.serialize('json', objs)
    return HttpResponse(jsondata, content_type='application/json')
Raptor
источник
Вы можете использовать JsonResponse
MichielB
2

Вы также можете проверить тип содержимого для принятия запроса, указанный в файле rfc. Таким образом, вы можете отображать HTML по умолчанию, и если ваш клиент принимает приложение / jason, вы можете вернуть json в свой ответ без необходимости шаблона

Грег
источник
2
from django.utils import simplejson 
from django.core import serializers 

def pagina_json(request): 
   misdatos = misdatos.objects.all()
   data = serializers.serialize('json', misdatos) 
   return HttpResponse(data, mimetype='application/json')
user3654231
источник
1

Вот пример, который мне нужен для условного рендеринга json или html в зависимости от Acceptзаголовка запроса

# myapp/views.py
from django.core import serializers                                                                                
from django.http import HttpResponse                                                                                  
from django.shortcuts import render                                                                                   
from .models import Event

def event_index(request):                                                                                             
    event_list = Event.objects.all()                                                                                  
    if request.META['HTTP_ACCEPT'] == 'application/json':                                                             
        response = serializers.serialize('json', event_list)                                                          
        return HttpResponse(response, content_type='application/json')                                                
    else:                                                                                                             
        context = {'event_list': event_list}                                                                          
        return render(request, 'polls/event_list.html', context)

вы можете проверить это с помощью curl или httpie

$ http localhost:8000/event/
$ http localhost:8000/event/ Accept:application/json

note Я решил не использовать, JsonReponseпоскольку это приведет к повторной сериализации модели без необходимости.

Гарри Морено
источник
0

Если вы хотите передать результат в виде отрисованного шаблона, вам нужно загрузить и отрендерить шаблон, передайте результат отрисовки в json. Это может выглядеть так:

from django.template import loader, RequestContext

#render the template
t=loader.get_template('sample/sample.html')
context=RequestContext()
html=t.render(context)

#create the json
result={'html_result':html)
json = simplejson.dumps(result)

return HttpResponse(json)

Таким образом вы можете передать отрисованный шаблон как json своему клиенту. Это может быть полезно, если вы хотите полностью заменить ie. a, содержащий множество различных элементов.

Marue
источник
1
В качестве побочного примечания, render_to_stringэто ярлык для трех строк «рендеринга шаблона», который существует с Django 1.0
Izkata