¿Dónde están mis datos JSON en mi solicitud entrante de Django?

162

Estoy tratando de procesar las solicitudes entrantes JSON / Ajax con Django / Python.

request.is_ajax()está Trueen la solicitud, pero no tengo idea de dónde está la carga útil con los datos JSON.

request.POST.dir contiene esto:

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

Aparentemente no hay claves en la solicitud de claves de publicación.

Cuando miro la POST en Firebug , se envían datos JSON en la solicitud.

Flimm
fuente
¿Qué estás realmente PUBLICANDO? Muéstranos la llamada de JavaScript.
Daniel Roseman
Y len(request.POST)y request.POST.items()también ayudaría.
Vinay Sajip

Respuestas:

233

Si está publicando JSON en Django, creo que lo desea request.body( request.raw_post_dataen Django <1.4). Esto le dará los datos JSON sin procesar enviados a través de la publicación. Desde allí puede procesarlo más.

Aquí hay un ejemplo usando JavaScript, jQuery , jquery-json y 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")
Jared Knipp
fuente
Por favor, explique a qué se refiere con "cliente de prueba". ¿Que estás tratando de hacer?
Jared Knipp
No estoy tratando de ser grosero: por "cliente de prueba", me refiero al "cliente de prueba" de django. ¿Cómo prueba las vistas si no con el cliente de prueba?
jMyles
44
Tenga en cuenta: debe terminar la url con barra (/) char. También deshabilite CSRF con @csrf_exempt
dani herrera
46
Nota: si está utilizando 1.4, esto se llamaría request.body. raw_post_data está en desuso ...
prauchfuss
3
para probar con django unittest acaba de hacerself.client.post('/event/save-json/', json.dumps(python_dict), HTTP_X_REQUESTED_WITH='XMLHttpRequest', content_type="application/json")
Guillaume Vincent
68

Yo tuve el mismo problema. Había estado publicando una respuesta JSON compleja, y no podía leer mis datos usando el diccionario request.POST.

Mi JSON POST data fue:

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

En este caso, debe utilizar el método proporcionado por aurealus. Lee request.body y deserialízalo con 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
fuente
2
Tengo problemas con la cuarta línea: json_data = simplejson.loads(request.raw_post_data)¿estás seguro de que se ha indicado correctamente?
wfbarksdale
Estoy bastante seguro de que request.raw_post_data es la forma correcta, ya que utilicé este ejemplo en las pruebas. ¿Qué tipo de problemas tienes @weezybizzle?
stricjux
1
Los datos que venían en algún texto adicional también se agregaron a eso que estaba arruinando el análisis. Entonces era 100% yo.
wfbarksdale
44
django.utils.simplejsonSe ha eliminado en versiones recientes. Solo usa la jsonbiblioteca stdlib .
Martijn Pieters
Querrá
38

Método 1

Cliente: Enviar como 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}

Servidor:

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

Método 2

Cliente: Enviar como x-www-form-urlencoded
(Nota: contentType& processDataha cambiado, JSON.stringifyno es necesario)

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

Servidor:

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

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

Datos no formales en solicitudes HTTP :
request.POST ya no incluirá datos publicados a través de solicitudes HTTP con tipos de contenido no específicos del formulario en el encabezado. En versiones anteriores, los datos publicados con tipos de contenido distintos de multipart / form-data o application / x-www-form-urlencoded seguirían representados en el atributo request.POST. Los desarrolladores que deseen acceder a los datos POST sin procesar para estos casos, deben usar el atributo request.body en su lugar.

Probablemente relacionado

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

Es importante recordar que Python 3 tiene una forma diferente de representar cadenas: son conjuntos de bytes.

Usando Django 1.9 y Python 2.7 y enviando los datos JSON en el cuerpo principal (no un encabezado) usaría algo como:

mydata = json.loads(request.body)

Pero para Django 1.9 y Python 3.4 usaría:

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

¡Acabo de pasar por esta curva de aprendizaje haciendo mi primera aplicación Py3 Django!

Richard Cooke
fuente
3
¡Gracias por su explicación! Estoy usando Django 1.10 y Python 3.5, ¡mydata = json.loads (request.body.decode ("utf-8")) funciona!
Julia Zhao
23

request.raw_responseahora está en desuso. Utilice en su request.bodylugar para procesar datos de formularios no convencionales, como cargas útiles XML, imágenes binarias, etc.

Documentación de Django sobre el tema .

Kevin S Lin
fuente
9

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

servidor

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")))
Pato de goma
fuente
5

La carga útil HTTP POST es solo un conjunto plano de bytes. Django (como la mayoría de los frameworks) lo decodifica en un diccionario desde parámetros codificados por URL o codificación MIME-multipart. Si solo vuelca los datos JSON en el contenido POST, Django no lo decodificará. O bien la decodificación JSON del contenido POST completo (no el diccionario); o coloque los datos JSON en un contenedor MIME-multipart.

En resumen, muestre el código JavaScript. El problema parece estar ahí.

Javier
fuente
¡Ahora veo el problema! El parámetro type = 'json' en jquery se refiere a qué tipo esperar, no a lo que envía. Está enviando datos codificados de forma regular, por lo que si quiero enviar "json", necesito convertirlo de alguna manera en una cadena y pasar "json = {foo: bar,}", etc. cómo lo hace la mayoría de la gente. Debo estar perdiendo algo aquí.
En realidad, puede convertir el formulario en una cadena JSON en jQuery con la función .serialize (). Pero, ¿por qué necesitas enviar especialmente a json? ¿Qué hay de malo con solo enviar los datos del formulario?
Daniel Roseman
44
Hay muchos casos en los que los datos sin formato no son suficientes; JSON le permite enviar objetos jerárquicos, no solo pares clave: valor. Puede enviar conjuntos anidados, matrices, etc. Probablemente podría hacer todo eso con datos de publicación, pero no es tan conveniente. Es un poco agradable tratar siempre con JSON, tanto de
ida
5

request.raw_post_dataha quedado en desuso Utilizar en su request.bodylugar

Andres
fuente
Gracias por esto! Funcionó perfectamente.
Prometeo
4

Algo como esto. Funcionó: solicitar datos del cliente

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

Procesar solicitud en el servidor

@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")
Nghia Tu
fuente
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))
Rajan Mandanka
fuente
-2

Usando Angular, debe agregar un encabezado para solicitar o agregarlo a los encabezados de configuración del módulo: {'Content-Type': 'application/x-www-form-urlencoded'}

$http({
    url: url,
    method: method,
    timeout: timeout,
    data: data,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
Mikalai Naunyka
fuente
-4

request.POST es solo un objeto similar a un diccionario, así que solo indexe con sintaxis dict.

Suponiendo que su campo de formulario es fred, podría hacer algo como esto:

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

Alternativamente, use un objeto de formulario para manejar los datos POST.

Michael van der Westhuizen
fuente
Estaba buscando en request.POST ['json'] que no contenía nada. len fue 0
Entonces definitivamente ayudaría ver su llamada de JavaScript, como Daniel sugirió.
Vinay Sajip
13
request.POST solo se completa cuando el cuerpo de la solicitud POST está codificado en Form, de lo contrario está vacío.
Slacy