Wie kann ich JSON zurückgeben, ohne eine Vorlage in Django zu verwenden?

80

Dies hängt mit dieser Frage zusammen: Django gibt je nach Client-Python json und html zurück


Ich habe eine Befehlszeilen-Python-API für eine Django-App. Wenn ich über die API auf die App zugreife, sollte sie JSON und mit einem Browser HTML zurückgeben. Ich kann verschiedene URLs verwenden, um auf die verschiedenen Versionen zuzugreifen. Wie kann ich jedoch die HTML-Vorlage und JSON in der Datei views.py mit nur einer Vorlage rendern ?

Um den HTML-Code zu rendern, würde ich Folgendes verwenden:

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

Aber wie würde ich dasselbe für JSON tun, ohne eine JSON-Vorlage einzufügen? (das content-typesollte application/jsonstatt sein text/html)

Was würde die JSON- und HTML-Ausgaben bestimmen?

Also aus meiner Sicht .

if something:
    return render_to_response('html_template',.....)
else:
    return HttpReponse(jsondata,mimetype='application/json')
Neeran
quelle
@Marcin Du hast ihm im Grunde gesagt "Nein, mach es nicht so", ohne ihm ein Beispiel für den richtigen Weg zu zeigen. Dafür scheint dieser hier zu sein ...
Izkata,
@ Jimmy, wenn das passiert ist, hättest du Marcins Antwort auf die andere Frage nicht so schnell akzeptieren sollen. Warten Sie mindestens einen Tag, wahrscheinlich hätte jemand mit etwas wie Uku Loskits Antwort
geantwortet
@Izkata: Ich habe ihm tatsächlich gesagt, welche Bibliothek er verwenden soll. Diese Frage scheint dazu gedacht zu sein, jemanden dazu zu bringen, seinen Code für ihn zu schreiben.
Marcin

Antworten:

129

Ich denke, das Problem ist verwirrt, was Sie wollen. Ich kann mir vorstellen, dass Sie nicht wirklich versuchen, den HTML-Code in die JSON-Antwort einzufügen, sondern alternativ entweder HTML oder JSON zurückgeben möchten.

Zunächst müssen Sie den Kernunterschied zwischen den beiden verstehen. HTML ist ein Präsentationsformat. Es geht mehr um die Anzeige von Daten als um die Daten selbst. JSON ist das Gegenteil. Es sind reine Daten - im Grunde eine JavaScript-Darstellung eines Python-Datensatzes (in diesem Fall), den Sie haben. Es dient lediglich als Austauschschicht, mit der Sie Daten aus einem Bereich Ihrer App (der Ansicht) in einen anderen Bereich Ihrer App (Ihr JavaScript) verschieben können, die normalerweise keinen Zugriff aufeinander haben.

In diesem Sinne "rendern" Sie JSON nicht und es sind keine Vorlagen beteiligt. Sie konvertieren lediglich alle im Spiel befindlichen Daten (höchstwahrscheinlich so ziemlich das, was Sie als Kontext an Ihre Vorlage übergeben) in JSON. Dies kann entweder über die JSON-Bibliothek von Django (simplejson) erfolgen, wenn es sich um Freiformdaten handelt, oder über das Serialisierungsframework, wenn es sich um ein Abfrageset handelt.

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)

Serialisierung

from django.core import serializers

foos = Foo.objects.all()

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

In beiden Fällen übergeben Sie diese Daten dann an die Antwort:

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

[Bearbeiten] In Django 1.6 und früheren Versionen war der Code für die Rückgabe der Antwort

return HttpResponse(data, mimetype='application/json')
Chris Pratt
quelle
Vielen Dank für die Klarstellung. Wie stelle ich in meinen Ansichten fest, dass die Antwortanforderung von der API für den JSON stammt? Siehe Bearbeiten bei Frage.
Neeran
1
Sie können verwenden request.is_ajax(). Dies setzt jedoch voraus, dass der HTTP_X_REQUESTED_WITHHeader gesetzt ist. Die meisten JavaScript-Bibliotheken tun dies automatisch. Wenn Sie jedoch einen anderen Client-Typ verwenden, müssen Sie sicherstellen, dass dieser ebenfalls festgelegt wird. Alternativ können Sie einen Querystring wie ?jsonmit der URL übergeben und dann überprüfen request.GET.has_key('json'), was wahrscheinlich etwas narrensicherer ist.
Chris Pratt
16
Beachten Sie, dass simplejson jetzt von Django 1.5 als veraltet angesehen wird . Verwenden Sie import json ; json.dumps(data)stattdessen.
Yonatan
1
Das OP sollte den Verhandlungsheader für den Inhaltstyp "Akzeptieren" im requestObjekt überprüfen . Siehe: w3.org/Protocols/rfc2616/rfc2616-sec14.html (großes Beispiel für einen Lesevorgang, aber ein vereinfachtes Codebeispiel könnte verwendet werden, um dies zu demonstrieren, und es wäre nicht sehr schwierig, ein unflexibles System zu schreiben, das dies zumindest tun würde behandeln Sie die zwei Fälle, die sie fragen)
Merlyn Morgan-Graham
14
In meinem Fall (Django 1.7) war es content_type = 'application / json', nicht mimetype
Nopik
8

Bei der JSON-Antwort muss keine Vorlage gerendert werden. Vorlagen dienen zum Generieren von HTML-Antworten. Der JSON ist die HTTP-Antwort.

Sie können jedoch HTML verwenden, das mit Ihrer JSON-Antwort aus einer Vorlage gerendert wird.

html = render_to_string("some.html", some_dictionary)
serialized_data = simplejson.dumps({"html": html})
return HttpResponse(serialized_data, mimetype="application/json")
Uku Loskit
quelle
Muss ich zuerst die Objekte serialisieren?
Neeran
simplejson.dumps () führt die Serialisierung durch.
Uku Loskit
Danke, es funktioniert absolut gut. wir können json auch anstelle von simplejson verwenden @UkuLoskit
Chirag Kanzariya
7

Es sieht so aus, als ob das Django REST-Framework den HTTP-Accept-Header in einer Anfrage verwendet, um automatisch zu bestimmen, welcher Renderer verwendet werden soll:

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

Die Verwendung des HTTP-Accept-Headers bietet möglicherweise eine alternative Quelle für Ihr "Wenn etwas".

Charles Brandt
quelle
7

Um meine Modelle in JSON in Django 1.9 zu rendern, musste ich in meinen views.py Folgendes tun:

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')
Raubvogel
quelle
Sie können JsonResponse
MichielB
2

Sie können auch überprüfen, ob die Anforderung den Inhaltstyp akzeptiert, wie im RFC angegeben. Auf diese Weise können Sie standardmäßig HTML rendern und wenn Ihr Client Anwendung / Jason akzeptiert, können Sie json in Ihrer Antwort zurückgeben, ohne dass eine Vorlage erforderlich ist

Greg
quelle
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
quelle
1

Hier ist ein Beispiel, das ich zum bedingten Rendern von JSON oder HTML je nach AcceptHeader der Anforderung benötigte

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

Sie können dies mit Curl oder httpie testen

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

Hinweis Ich habe mich für JsonReponsedie Nichtverwendung entschieden, da dies das Modell unnötig reserialisieren würde .

Harry Moreno
quelle
0

Wenn Sie das Ergebnis als gerenderte Vorlage übergeben möchten, müssen Sie eine Vorlage laden und rendern. Übergeben Sie das Ergebnis des Renderns an json. Dies könnte folgendermaßen aussehen:

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)

Auf diese Weise können Sie eine gerenderte Vorlage als JSON an Ihren Client übergeben. Dies kann nützlich sein, wenn Sie vollständig ersetzen möchten, z. a enthält viele verschiedene Elemente.

marue
quelle
1
Als Randnotiz, render_to_stringist eine Verknüpfung für die 3 "Rendern der Vorlage" Zeilen, und existiert seit Django 1.0
Izkata