我的Django请求中的JSON数据在哪里?

203

我正在尝试使用Django/Python处理传入的JSON/Ajax请求。

request.is_ajax() 在请求中为True,但我不知道JSON数据的负载在哪里。

request.POST.dir 包含如下内容:

['__class__', '__cmp__', '__contains__', '__copy__', '__deepcopy__', '__delattr__',
 '__delitem__', '__dict__', '__doc__', '__eq__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__',
 '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__setitem__', '__str__', '__weakref__', '_assert_mutable', '_encoding', 
'_get_encoding', '_mutable', '_set_encoding', 'appendlist', 'clear', 'copy', 'encoding', 
'fromkeys', 'get', 'getlist', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 
'keys', 'lists', 'pop', 'popitem', 'setdefault', 'setlist', 'setlistdefault', 'update', 
'urlencode', 'values']

请求中似乎没有键。

当我在Firebug中查看POST时,可以看到请求中发送了JSON数据。


你实际上正在 POST 什么?展示给我们 JavaScript 调用。 - Daniel Roseman
len(request.POST)request.POST.items()也会有所帮助。 - Vinay Sajip
13个回答

266
如果您要向Django发布JSON,则需要使用request.body(在Django<1.4中为request.raw_post_data)。这将提供通过post发送的原始JSON数据。从那里,您可以进一步处理它。
以下是使用JavaScript、jQuery、jquery-json和Django的示例:
JavaScript:
var myEvent = {id: calEvent.id, start: calEvent.start, end: calEvent.end,
               allDay: calEvent.allDay };
$.ajax({
    url: '/event/save-json/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: $.toJSON(myEvent),
    dataType: 'text',
    success: function(result) {
        alert(result.Result);
    }
});

Django:

def save_events_json(request):
    if request.is_ajax():
        if request.method == 'POST':
            print 'Raw Data: "%s"' % request.body   
    return HttpResponse("OK")

Django < 1.4:

->

Django小于1.4版本:

  def save_events_json(request):
    if request.is_ajax():
        if request.method == 'POST':
            print 'Raw Data: "%s"' % request.raw_post_data
    return HttpResponse("OK")

4
请注意:您应该在 URL 末尾添加斜杠(/)字符。另外,请使用 @csrf_exempt 禁用 CSRF。 - dani herrera
47
如果您使用的是1.4版本,那么这将被称为request.body。raw_post_data已经过时了。 - prauchfuss
3
要使用Django单元测试进行测试,只需执行self.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json") - Guillaume Vincent
请注意,这段Django代码始终返回200响应,即使请求方法是错误的。我不是要表现得聪明,但我经常看到工程师在实际代码中这样做,这会使前端编码更加困难。在这种情况下,return HttpResponseBadRequest()return HttpResponseNotAllowed(['POST'])是适当的else子句。 - Michael Scheper
并没有真正回答 OP 的问题。他想要 JSON 数据,而不是存储在 request.body 中的 JSON 数据字符串。您没有提到 OP 需要解析该字符串。 - Cerin
显示剩余2条评论

91

我曾遇到同样的问题。我一直在提交一个复杂的JSON响应,但我无法使用request.POST字典读取我的数据。

我的JSON POST数据是:

//JavaScript code:
//Requires json2.js and jQuery.
var response = {data:[{"a":1, "b":2},{"a":2, "b":2}]}
json_response = JSON.stringify(response); // proper serialization method, read 
                                          // http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
$.post('url',json_response);

在这种情况下,您需要使用aurealus提供的方法。读取request.body,并使用json stdlib进行反序列化。

#Django code:
import json
def save_data(request):
  if request.method == 'POST':
    json_data = json.loads(request.body) # request.raw_post_data w/ Django < 1.4
    try:
      data = json_data['data']
    except KeyError:
      HttpResponseServerError("Malformed data!")
    HttpResponse("Got json data")

2
我在第四行遇到了问题:json_data = simplejson.loads(request.raw_post_data),你确定这句话说得对吗? - wfbarksdale
我非常确定request.raw_post_data是正确的形式,因为我在测试中使用了这个例子。@weezybizzle,你遇到了什么问题? - stricjux
1
数据中附加了一些额外的文本,导致解析出现问题。所以这完全是我的错。 - wfbarksdale
4
在最近的版本中,删除了django.utils.simplejson。只需使用标准库中的json库即可。 - Martijn Pieters
你应该在Django 1.4+中使用request.body而不是request.raw_post_data。 - mrooney

46

方法一

客户端:以JSON格式发送

$.ajax({
    url: 'example.com/ajax/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    processData: false,
    data: JSON.stringify({'name':'John', 'age': 42}),
    ...
});

//Sent as a JSON object {'name':'John', 'age': 42}

服务器 :

data = json.loads(request.body) # {'name':'John', 'age': 42}

方法2

客户端: 以x-www-form-urlencoded格式发送请求
(注意:contentTypeprocessData已更改,不需要使用JSON.stringify

$.ajax({
    url: 'example.com/ajax/',
    type: 'POST',    
    data: {'name':'John', 'age': 42},
    contentType: 'application/x-www-form-urlencoded; charset=utf-8',  //Default
    processData: true,       
});

//Sent as a query string name=John&age=42

服务器:

data = request.POST # will be <QueryDict: {u'name':u'John', u'age': 42}>

自1.5版本开始有所更改:https://docs.djangoproject.com/en/dev/releases/1.5/#non-form-data-in-http-requests

HTTP请求中的非表单数据
request.POST将不再包括在头部使用非特定于表单的内容类型进行HTTP请求发布的数据。在之前的版本中,使用multipart/form-data或application/x-www-form-urlencoded以外的内容类型发布的数据仍然会被表示为请求的request.POST属性。希望访问这些情况下的原始POST数据的开发人员应该使用request.body属性。

可能相关:


3
django.http.request.RawPostDataException: 在从请求数据流中读取后,您无法访问正文。 - AlxVallejo

28

重要的是要记住Python 3有一种不同的表示字符串的方式 - 它们是字节数组。

使用Django 1.9和Python 2.7,并在主体中发送JSON数据(而不是标题),您可以使用类似以下代码:

mydata = json.loads(request.body)

但对于 Django 1.9 和 Python 3.4,您需要使用:

mydata = json.loads(request.body.decode("utf-8"))

我刚刚通过这个学习曲线完成了我的第一个 Py3 Django 应用程序!


4
谢谢您的解释!我正在使用Django 1.10和Python 3.5,mydata = json.loads(request.body.decode("utf-8")) 工作正常! - Julia Zhao

23

request.raw_response已被弃用。现在应该使用request.body来处理非传统表单数据,例如XML负载、二进制图像等。

Django文档中有相关说明


9
在Django 1.6和Python 3.3中,客户端的相关内容。
$.ajax({
    url: '/urll/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(json_object),
    dataType: 'json',
    success: function(result) {
        alert(result.Result);
    }
});

服务器

def urll(request):

if request.is_ajax():
    if request.method == 'POST':
        print ('Raw Data:', request.body) 

        print ('type(request.body):', type(request.body)) # this type is bytes

        print(json.loads(request.body.decode("utf-8")))

Django 4+中已删除request.is_ajax() https://docs.djangoproject.com/en/4.0/releases/3.1/#id2 - Ryan

6

类似这样的. 它是有效的: 从客户端请求数据

registerData = {
{% for field in userFields%}
  {{ field.name }}: {{ field.name }},
{% endfor %}
}


var request = $.ajax({
   url: "{% url 'MainApp:rq-create-account-json' %}",
   method: "POST",
   async: false,
   contentType: "application/json; charset=utf-8",
   data: JSON.stringify(registerData),
   dataType: "json"
});

request.done(function (msg) {
   [alert(msg);]
   alert(msg.name);
});

request.fail(function (jqXHR, status) {
  alert(status);
});

在服务器上处理请求

@csrf_exempt
def rq_create_account_json(request):
   if request.is_ajax():
       if request.method == 'POST':
           json_data = json.loads(request.body)
           print(json_data)
           return JsonResponse(json_data)
   return HttpResponse("Error")

5

request.raw_post_data已经被弃用。请使用request.body代替。


5
HTTP POST载荷只是一堆平面字节。 Django(像大多数框架一样)将其从URL编码参数或MIME多部分编码解码为字典。 如果您只是将JSON数据转储到POST内容中,则Django不会对其进行解码。 要么从完整的POST内容(而不是字典)进行JSON解码;要么将JSON数据放入MIME多部分包装器中。
简而言之,请展示JavaScript代码。 问题似乎就在那里。

我现在明白问题了!JQuery中的type='json'参数是指期望接收的数据类型,而不是发送的数据类型。它正在发送常规表单编码数据,因此如果我想要发送“json”,我需要将其转换为字符串,并传递“json={foo:bar, }”等内容。然而,我无法相信大多数人都是这样做的。我一定是在这里漏掉了什么。 - user122299
实际上,您可以使用jQuery中的.serialize()函数将表单转换为JSON字符串。但是,您为什么特别需要发送json呢?直接发送表单数据有什么问题吗? - Daniel Roseman
4
有许多情况下,原始表单数据并不足够;JSON 允许您发送分层对象,而不仅仅是键值对。 您可以发送嵌套集合、数组等。虽然您可以使用 post 数据完成所有这些操作,但这样做并不方便。使用 JSON 来回传递数据是一种比较方便的方式。 - taxilian

2
html code 

file name  : view.html


    <!DOCTYPE html>
    <html>
    <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
    $(document).ready(function(){
        $("#mySelect").change(function(){
            selected = $("#mySelect option:selected").text()
            $.ajax({
                type: 'POST',
                dataType: 'json',
                contentType: 'application/json; charset=utf-8',
                url: '/view/',
                data: {
                       'fruit': selected
                      },
                success: function(result) {
                        document.write(result)
                        }
        });
      });
    });
    </script>
    </head>
    <body>

    <form>
        <br>
    Select your favorite fruit:
    <select id="mySelect">
      <option value="apple" selected >Select fruit</option>
      <option value="apple">Apple</option>
      <option value="orange">Orange</option>
      <option value="pineapple">Pineapple</option>
      <option value="banana">Banana</option>
    </select>
    </form>
    </body>
    </html>

Django code:


Inside views.py


def view(request):

    if request.method == 'POST':
        print request.body
        data = request.body
        return HttpResponse(json.dumps(data))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接