如何在Django中不使用模板的情况下返回JSON?


81

这与此问题有关:Django根据客户端python返回json和html


我有一个适用于Django应用的命令行Python API。当我通过API访问该应用程序时,它应该返回JSON,而在浏览器中它应该返回HTML。我可以使用不同的URL来访问不同的版本,但是如何仅用一个模板在views.py中呈现HTML模板和JSON ?

要呈现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 2012年

@Jimmy,如果真是那样,您不应该这么快就接受Marcin对另一个问题的回答。等待至少一天,某人可能会用Uku Loskit的答案回答问题
Izkata 2012年

@Izkata:我确实告诉他要使用哪个库。这个问题似乎是为了让别人为他编写代码。
Marcin 2012年

Answers:


131

我认为这个问题对您想要的东西感到困惑。我想您实际上不是在尝试将HTML放入JSON响应中,而是想返回HTML或JSON。

首先,您需要了解两者之间的核心区别。HTML是一种表示形式。与数据本身相比,它更多地涉及如何显示数据。JSON相反。它是纯数据-基本上是您拥有的某些Python(在这种情况下)数据集的JavaScript表示形式。它仅用作交换层,使您可以将数据从应用程序的一个区域(视图)移动到应用程序的另一区域(您的JavaScript),而这些区域通常是无法相互访问的。

考虑到这一点,您无需“渲染” JSON,并且不涉及任何模板。您只需将正在使用的所有数据(很可能是您作为上下文传递给模板的数据)转换为JSON。如果是自由格式数据,则可以通过Django的JSON库(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')

[编辑]在Django 1.6及更早版本中,返回响应的代码为

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

[编辑]:simplejson已从django中删除,您可以使用:

import json

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

或者您可以使用django.core.serializers如上所述的。


谢谢您的澄清。如何在我的视图中确定响应请求是通过json的api进行的?请参阅有问题的编辑。
Neeran '02

1
您可以使用request.is_ajax()。但这需要HTTP_X_REQUESTED_WITH设置标头。大多数JavaScript库都会自动执行此操作,但是如果您使用其他类型的客户端,则需要确保它也进行了设置。另外,您可以传递一个?json带有URL的查询字符串,然后检查request.GET.has_key('json'),这可能更简单一些。
克里斯·普拉特

18
请注意,Django 1.5现在认为simplejson已弃用。使用import json ; json.dumps(data)代替。
Yonatan

1
OP应检查对象中的“接受”内容类型协商标头request。参见:w3.org/Protocols/rfc2616/rfc2616-sec14.html(阅读时花样百出,但是可以使用简化的代码示例进行演示,并且编写一个不灵活的系统至少会很困难,至少处理他们要问的两个案件)
Merlyn Morgan-Graham

14
就我而言(Django 1.7)是content_type ='application / json',而不是mimetype
Nopik 2014年


8

在JSON响应的情况下,没有要呈现的模板。模板用于生成HTML响应。JSON是HTTP响应。

但是,您可以使用从模板随JSON响应呈现的HTML。

html = render_to_string("some.html", some_dictionary)
serialized_data = simplejson.dumps({"html": html})
return HttpResponse(serialized_data, mimetype="application/json")

我必须先序列化对象吗?
Neeran '02

simplejson.dumps()是进行序列化的内容。
Uku Loskit

谢谢你的工作绝对好。我们也可以使用json代替simplejson @UkuLoskit
Chirag Kanzariya


7

为了在django 1.9中以JSON呈现模型,我必须在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')

您可以使用JsonResponse
MichielB

2

您还可以检查rfc中指定的请求接受内容类型。这样,您可以默认渲染HTML,并且在客户端接受应用程序/杰森的情况下,您可以在响应中返回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')

1

这是一个示例,我需要根据请求的Accept标头有条件地呈现json或html

# 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

注意我选择不使用,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,这将很有用。包含许多不同的元素。


1
作为一个侧面说明,render_to_string对于3“呈现模板”线的快捷方式,并自Django的1.0已经存在
Izkata
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.