¿Cómo devuelvo JSON sin usar una plantilla en Django?

81

Esto está relacionado con esta pregunta: Django devuelve json y html según el cliente python


Tengo una API de Python de línea de comandos para una aplicación de Django. Cuando accedo a la aplicación a través de la API, debería devolver JSON y con un navegador debería devolver HTML. Puedo usar diferentes URL para acceder a las diferentes versiones, pero ¿cómo renderizo la plantilla HTML y JSON en views.py con solo una plantilla?

Para renderizar el HTML usaría:

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

Pero, ¿cómo haría lo mismo para JSON sin poner una plantilla JSON? (el content-typedebería ser en application/jsonlugar de text/html)

¿Qué determinaría las salidas JSON y HTML?

Entonces en mi views.py :

if something:
    return render_to_response('html_template',.....)
else:
    return HttpReponse(jsondata,mimetype='application/json')
Neeran
fuente
@Marcin Básicamente le dijiste "No, no lo hagas de esta manera" sin mostrarle un ejemplo de la manera correcta. Para eso parece ser este ...
Izkata
@Jimmy, si eso es lo que pasó, no deberías haber aceptado la respuesta de Marcin a la otra pregunta tan rápido. Espere al menos un día, alguien probablemente habría respondido con algo como la respuesta de Uku Loskit
Izkata
@Izkata: De hecho, le dije qué biblioteca usar. Esta pregunta parece tener el propósito de hacer que otra persona escriba su código por él.
Marcin

Respuestas:

131

Creo que el tema se ha confundido con respecto a lo que quieres. Me imagino que en realidad no está tratando de poner HTML en la respuesta JSON, sino que desea devolver HTML o JSON alternativamente.

Primero, debe comprender la diferencia fundamental entre los dos. HTML es un formato de presentación. Se trata más de cómo mostrar datos que de los datos en sí. JSON es lo contrario. Son datos puros, básicamente una representación de JavaScript de algún conjunto de datos de Python (en este caso) que tiene. Sirve simplemente como una capa de intercambio, lo que le permite mover datos de un área de su aplicación (la vista) a otra área de su aplicación (su JavaScript) que normalmente no tienen acceso entre sí.

Con eso en mente, no "renderiza" JSON y no hay plantillas involucradas. Simplemente convierte cualquier dato que esté en juego (probablemente más o menos lo que está pasando como contexto a su plantilla) a JSON. Lo cual se puede hacer a través de la biblioteca JSON de Django (simplejson), si son datos de forma libre, o su marco de serialización, si es un conjunto de consultas.

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)

Publicación por entregas

from django.core import serializers

foos = Foo.objects.all()

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

De cualquier manera, luego pasa esos datos a la respuesta:

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

[Editar] En Django 1.6 y versiones anteriores, el código para devolver la respuesta era

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

[EDITAR]: simplejson fue eliminado de django , puedes usar:

import json

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

O puede usar el django.core.serializerscomo se describe arriba.

Chris Pratt
fuente
Gracias por la aclaración. ¿Cómo determino en mis puntos de vista que la solicitud de respuesta es por la api para el json? Ver la edición de la pregunta.
Neeran
1
Puede utilizar request.is_ajax(). Pero eso requiere que el HTTP_X_REQUESTED_WITHencabezado esté configurado. La mayoría de las bibliotecas de JavaScript hacen esto automáticamente, pero si está utilizando algún otro tipo de cliente, deberá asegurarse de que también lo configure. Alternativamente, puede pasar una cadena de consulta como ?jsoncon la URL y luego verificar request.GET.has_key('json'), que probablemente sea un poco más infalible.
Chris Pratt
18
Tenga en cuenta que simplejson ahora se considera obsoleto por Django 1.5 . Úselo en su import json ; json.dumps(data)lugar.
Yonatan
1
El OP debe comprobar el encabezado de negociación del tipo de contenido "Aceptar" en el requestobjeto. Ver: w3.org/Protocols/rfc2616/rfc2616-sec14.html (gran parte de una lectura, pero se podría usar una muestra de código simplificado para demostrar, y no sería muy difícil escribir un sistema inflexible que al menos manejar los dos casos que están preguntando)
Merlyn Morgan-Graham
14
En mi caso (Django 1.7) era content_type = 'application / json', no mimetype
Nopik
8

En el caso de la respuesta JSON, no hay ninguna plantilla para representar. Las plantillas sirven para generar respuestas HTML. El JSON es la respuesta HTTP.

Sin embargo, puede tener HTML que se procesa desde una plantilla dentro de su respuesta JSON.

html = render_to_string("some.html", some_dictionary)
serialized_data = simplejson.dumps({"html": html})
return HttpResponse(serialized_data, mimetype="application/json")
Uku Loskit
fuente
¿Tengo que serializar los objetos primero?
Neeran
simplejson.dumps () es lo que hace la serialización.
Uku Loskit
gracias, está funcionando absolutamente bien. también podemos usar json en lugar de simplejson @UkuLoskit
Chirag Kanzariya
7

Parece que el marco Django REST usa el encabezado de aceptación HTTP en una Solicitud para determinar automáticamente qué renderizador usar:

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

El uso del encabezado de aceptación HTTP puede proporcionar una fuente alternativa para su "si algo".

Charles Brandt
fuente
7

Para renderizar mis modelos en JSON en django 1.9 tuve que hacer lo siguiente en mi 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
fuente
Puede usar JsonResponse
MichielB
2

También puede verificar el tipo de contenido de aceptación de solicitud como se especifica en el rfc. De esa manera, puede renderizar por defecto HTML y donde su cliente acepta la aplicación / jason, puede devolver json en su respuesta sin que se requiera una plantilla

Greg
fuente
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')
usuario3654231
fuente
1

Aquí hay un ejemplo que necesitaba para renderizar json o html de forma condicional según el Acceptencabezado de la solicitud

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

puedes probar esto con curl o httpie

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

tenga en cuenta que opté por no usarlo JsonReponseya que reservaría el modelo innecesariamente.

Harry Moreno
fuente
0

Si desea pasar el resultado como una plantilla renderizada, debe cargar y renderizar una plantilla, pasar el resultado de renderizarla al json. Esto podría verse así:

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)

De esa manera, puede pasar una plantilla renderizada como json a su cliente. Esto puede ser útil si desea reemplazar completamente ie. que contiene muchos elementos diferentes.

marue
fuente
1
Como nota al margen, render_to_stringes un atajo para las 3 líneas "render the template", y existe desde Django 1.0
Izkata