Dove sono i miei dati JSON nella mia richiesta Django in arrivo?


162

Sto cercando di elaborare le richieste JSON / Ajax in arrivo con Django / Python.

request.is_ajax()è Truesulla richiesta, ma non ho idea di dove sia il payload con i dati JSON.

request.POST.dir contiene questo:

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

Apparentemente non ci sono chiavi nelle chiavi del post di richiesta.

Quando guardo il POST in Firebug , ci sono dati JSON inviati nella richiesta.


Cosa stai effettivamente postando? Mostraci la chiamata javascript.
Daniel Roseman,

E len(request.POST)e request.POST.items()aiuterebbe anche.
Vinay Sajip,

Risposte:


233

Se pubblichi JSON su Django, penso che tu voglia request.body( request.raw_post_datasu Django <1.4). Questo ti darà i dati JSON non elaborati inviati tramite posta. Da lì puoi elaborarlo ulteriormente.

Ecco un esempio usando JavaScript, jQuery , jquery-json e 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:

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

Spiegare cosa intendi per "client di prova"? Cosa stai cercando di fare?
Jared Knipp,

Non sto cercando di essere scortese: per "client di test" intendo django "client di test". Come testare le visualizzazioni se non con il client di test?
jMyles,

4
Ricorda: dovresti terminare l'URL con il carattere barra (/). Disattiva anche CSRF con @csrf_exempt
dani herrera il

46
NB se stai usando 1.4 questo si chiamerebbe request.body. raw_post_data è deprecato ...
prauchfuss

3
per provare con il django unittest basta fareself.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json")
Guillaume Vincent l'

68

Ho avuto lo stesso problema. Avevo pubblicato una risposta JSON complessa e non riuscivo a leggere i miei dati utilizzando il dizionario request.POST.

I miei dati POST JSON erano:

//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);

In questo caso è necessario utilizzare il metodo fornito da aurealus. Leggi il request.body e deserializzalo con il 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
Sto riscontrando problemi con la 4a riga: json_data = simplejson.loads(request.raw_post_data)sei sicuro che sia stato dichiarato correttamente?
wfbarksdale,

Sono abbastanza sicuro che request.raw_post_data sia la forma corretta come ho usato questo esempio nei test. Che tipo di problemi hai @weezybizzle?
Stricjux,

1
I dati che arrivano in qualche testo aggiuntivo hanno aggiunto anche quello che stava rovinando l'analisi. Quindi ero al 100%.
wfbarksdale,

4
django.utils.simplejsonè stato rimosso nelle versioni recenti. Basta usare la jsonlibreria stdlib .
Martijn Pieters

Ti consigliamo di utilizzare request.body invece di request.raw_post_data per Django 1.4+
mrooney,

38

Metodo 1

Cliente: Invia come 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}

Server :

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

Metodo 2

Cliente: Invia come x-www-form-urlencoded
(Nota: contentTypee processDatasono cambiati, JSON.stringifynon è necessario)

$.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

Server :

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

Modificato in 1.5+: https://docs.djangoproject.com/en/dev/releases/1.5/#non-form-data-in-http-requests

Dati non in forma nelle richieste HTTP :
request.POST non includerà più i dati pubblicati tramite richieste HTTP con tipi di contenuto non specifici del modulo nell'intestazione. Nelle versioni precedenti, i dati pubblicati con tipi di contenuto diversi da multipart / form-data o application / x-www-form-urlencoded sarebbero comunque rappresentati nell'attributo request.POST. Gli sviluppatori che desiderano accedere ai dati POST non elaborati per questi casi, dovrebbero invece utilizzare l'attributo request.body.

Probabilmente correlato


3
Ri 1 -django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
AlxVallejo

24

È importante ricordare che Python 3 ha un modo diverso di rappresentare le stringhe: sono array di byte.

Usando Django 1.9 e Python 2.7 e inviando i dati JSON nel corpo principale (non un'intestazione) useresti qualcosa del tipo:

mydata = json.loads(request.body)

Ma per Django 1.9 e Python 3.4 useresti:

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

Ho appena attraversato questa curva di apprendimento realizzando la mia prima app Py3 Django!


3
Grazie per la tua spiegazione! Sto usando Django 1.10 e Python 3.5, mydata = json.loads (request.body.decode ("utf-8")) funziona!
Julia Zhao,


9

su django 1.6 python 3.3

cliente

$.ajax({
    url: '/urll/',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(json_object),
    dataType: 'json',
    success: function(result) {
        alert(result.Result);
    }
});

server

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

Il payload HTTP POST è solo un mucchio di byte. Django (come la maggior parte dei framework) lo decodifica in un dizionario da parametri con codifica URL o codifica MIME multipart. Se scarichi semplicemente i dati JSON nel contenuto POST, Django non li decodificherà. O esegui la decodifica JSON dal contenuto POST completo (non dal dizionario); oppure inserire i dati JSON in un wrapper MIME multipart.

In breve, mostra il codice JavaScript. Il problema sembra essere lì.


Vedo il problema ora! Il parametro type = 'json' in jquery si riferisce a quale tipo aspettarsi, non a ciò che invia. Sta inviando regolarmente dati codificati in formato post, quindi se voglio inviare "json" devo in qualche modo convertirli in una stringa e passare "json = {foo: bar,}" ecc. Non posso credere, tuttavia, che sia come la maggior parte delle persone lo fa. Qui mi sta sfuggendo qualcosa.

In realtà è possibile convertire il modulo in una stringa JSON in jQuery con la funzione .serialize (). Ma perché, in particolare, devi inviare json? Cosa c'è di sbagliato nell'invio dei dati del modulo?
Daniel Roseman,

4
Esistono molti casi in cui i dati di modulo non elaborati non sono sufficienti; JSON ti consente di inviare oggetti gerarchici, non solo coppie chiave: valore. Puoi inviare set nidificati, array, ecc. Probabilmente potresti farlo con i dati di post, ma non è così conveniente. E 'un pò bello a che fare solo con JSON sempre, sia da e per
taxilian

5

request.raw_post_dataè stato deprecato. Usa request.bodyinvece


Grazie per questo! Ha funzionato perfettamente.
Prometeo

4

Qualcosa come questo. Ha funzionato: richiedere i dati dal client

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);
});

Richiesta di processo sul server

@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

Utilizzando Angular è necessario aggiungere l'intestazione per richiedere o aggiungerlo alle intestazioni di configurazione del modulo: {'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 è solo un oggetto simile a un dizionario, quindi indicizzalo con la sintassi dict.

Supponendo che il tuo campo modulo sia fred, potresti fare qualcosa del genere:

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

In alternativa, utilizzare un oggetto modulo per gestire i dati POST.


Stavo cercando in request.POST ['json'] che non conteneva nulla. len aveva 0

Quindi sarebbe sicuramente utile vedere la tua chiamata JavaScript, come ha suggerito Daniel.
Vinay Sajip,

13
request.POST viene popolato solo quando il corpo della richiesta POST è codificato in Form, altrimenti è vuoto.
slacy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.