Где мои данные JSON во входящем запросе Django?

162

Я пытаюсь обработать входящие запросы JSON / Ajax с Django / Python.

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']

Похоже, в запросе нет ключей.

Когда я смотрю на POST в Firebug , в запросе передаются данные JSON.

Флимм
источник
Что вы на самом деле POSTing? Покажите нам вызов JavaScript.
Даниэль Роузман
И len(request.POST)и request.POST.items()также поможет.
Vinay Sajip

Ответы:

233

Если вы публикуете JSON в Django, я думаю, что вы хотите request.body( request.raw_post_dataв Django <1.4). Это даст вам необработанные данные 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);
    }
});

Джанго:

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

Джанго <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")
Джаред Книпп
источник
Пожалуйста, объясните, что вы подразумеваете под «тестовым клиентом»? Что ты пытаешься сделать?
Джаред Книпп
Я не пытаюсь быть грубым: под «тестовым клиентом» я подразумеваю django «тестовый клиент». Как вы тестируете представления, если не с тестовым клиентом?
jMyles
4
Помните: URL должен заканчиваться косой чертой (/). Также отключить CSRF с @csrf_exempt
дани Эррера
46
Примечание: если вы используете 1.4, это будет называться request.body. raw_post_data устарела ...
prauchfuss
3
чтобы проверить с django unittest просто сделайтеself.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json")
Гийом Винсент
68

У меня такая же проблема. Я публиковал сложный ответ 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")
stricjux
источник
2
У меня проблемы с 4-й строкой: json_data = simplejson.loads(request.raw_post_data)вы уверены, что правильно написали?
wfbarksdale
Я совершенно уверен, что request.raw_post_data является правильной формой, так как я использовал этот пример в тестировании. Какие проблемы у вас есть @weezybizzle?
stricjux
1
Данные, поступающие в каком-то дополнительном тексте, также добавляли это, что испортило синтаксический анализ. Так что это был 100% я.
wfbarksdale
4
django.utils.simplejsonбыл удален в последних версиях. Просто используйте jsonбиблиотеку stdlib .
Мартин Питерс
Вы захотите использовать request.body вместо request.raw_post_data для Django 1.4+
mrooney
38

Способ 1

Клиент: Отправить как 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
(Примечание: contentType& processDataизменилось, 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
Re 1 -django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
AlxVallejo
24

Важно помнить, что в 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!

Ричард Кук
источник
3
Спасибо за ваше объяснение! Я использую Django 1.10 и Python 3.5, mydata = json.loads (request.body.decode ("utf-8")) работает!
Юлия Чжао
9

на джанго 1.6 питон 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")))
Резиновая утка
источник
5

Полезная нагрузка HTTP POST - это просто набор байтов. Django (как и большинство фреймворков) декодирует его в словарь из параметров, закодированных в URL, или из MIME-multipart-кодирования. Если вы просто сбросите данные JSON в содержимом POST, Django не будет их декодировать. Либо выполните JSON-декодирование из полного содержимого POST (не из словаря); или поместите данные JSON в многокомпонентную оболочку MIME.

Короче, покажи код JavaScript. Проблема, кажется, там.

Хавьер
источник
Теперь я вижу проблему! Параметр type = 'json' в jquery указывает, какого типа ожидать, а не того, что он отправляет. Он отправляет обычную форму пост-закодированных данных, поэтому, если я хочу отправить «json», мне нужно каким-то образом преобразовать его в строку и передать «json = {foo: bar,}» и т. Д. Однако я не могу поверить, что это как большинство людей делают это. Я должен что-то здесь упустить.
На самом деле вы можете преобразовать форму в строку JSON в jQuery с помощью функции .serialize (). Но зачем вам отправлять JSON? Что не так просто отправить данные формы?
Даниэль Роузман
4
Во многих случаях необработанных данных формы недостаточно; JSON позволяет отправлять иерархические объекты, а не только пары ключ: значение. Вы можете отправлять вложенные наборы, массивы и т. Д. Вы, вероятно, могли бы делать все это с данными постов, но это не так удобно. Приятно просто всегда иметь дело с JSON, от и до
таксилист
5

request.raw_post_dataбыл объявлен устаревшим Используйте request.bodyвместо

Andres
источник
Спасибо тебе за это! Работал отлично.
Прометей
4

Что-то вроде этого. Работает: запрос данных от клиента

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")
Нгиа Ту
источник
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))
Раджан Манданка
источник
-2

Используя Angular, вы должны добавить заголовок к запросу или добавить его в заголовки конфигурации модуля: {'Content-Type': 'application/x-www-form-urlencoded'}

$http({
    url: url,
    method: method,
    timeout: timeout,
    data: data,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
Николай Науника
источник
-4

request.POST - это просто словарь-подобный объект, поэтому просто индексируйте его с помощью синтаксиса dict.

Предполагая, что ваше поле формы fred, вы можете сделать что-то вроде этого:

if 'fred' in request.POST:
    mydata = request.POST['fred']

В качестве альтернативы используйте объект формы для работы с данными POST.

Майкл ван дер Вестхайзен
источник
Я искал в request.POST ['json'], который ничего не содержал. len было 0
Тогда это определенно поможет увидеть ваш вызов JavaScript, как предложил Даниэль.
Vinay Sajip
13
request.POST заполняется только тогда, когда тело запроса POST закодировано в форме, в противном случае оно пустое.
рабство