2011-06-11 8 views
5

Experimento un comportamiento realmente extraño cuando uso el cliente de prueba en django.Comportamiento extraño de Django Querydict: agrupa el diccionario POST en una sola clave

Estoy usando un POST para enviar datos a mi aplicación django. Normalmente hago esto desde una aplicación de iPhone y/o un formulario html de prueba. En el lado del servidor, así es como lo manejo:

def handle_query(request): 
    print request 
    q = con.QueryLog() 
    q.ID = request.POST.get('ID', '') 
    q.device = request.POST.get('device-model', '') 
    .... 

Esa declaración de impresión se parece a lo que cabría esperar, es decir, cada parámetro en la petición de entrada se convierte en una clave en el diccionario:

la POST : QueryDict: {u'app-versión ': [u'3.0'], u'server-versión ': [u'v3d0'],

Sin embargo, comencé a escribir algunas pruebas utilizando el cliente de prueba de Django, y no importa lo que intento, el diccionario de parámetros de POST que envío en la solicitud de publicación se agrupan en una sola clave en el QueryDict. Permítanme ilustrar con algo de código:

clase SearchTest (TestCase): definición de configuración (auto): pase

def test_search(self): 
    request = HttpRequest() 
    data = '{"amzn_locale": "com"}' 
    # request._raw_post_data = data 
    resp = self.client.post(
     '/is/', 
     data=data, 
     content_type='application/x-www-form-urlencoded', 
     # content_type='application/json', 
     ) 

La misma declaración de impresión en el lado del servidor muestra la agrupación inexplicable del diccionario en una cadena:

POST: QueryDict: {u'{"amzn_locale":"com"}': [u'']}>, 

Si fijo de datos a un diccionario real, lo mismo

data = {"amzn_locale": "com"} 

Establecer el request._raw_post_data no cambia nada. Tampoco cambia

content_type='application/json' 

Cualquier ayuda sería muy apreciada. De esta cuestión stackoverflow parece que no soy el primero en encontrarse con este iphone Json POST request to Django server creates QueryDict within QueryDict

+0

Gabi Gracias por la edición – Andres

Respuesta

7

El problema es que está suministrando un content_type. Dado que usted lo hizo, el cliente está esperando una cadena urlencoded como

"username=hi&password=there&this_is_the_login_form=1" 

en lugar de un diccionario como

{'username': 'hi', 'password': 'there', 'this_is_the_login_form': 1} 

Si se quita la content_type kwarg se le multa.

Editar: Como resultado, el cliente de prueba buscará una cadena codificada en url si pasa en cualquier content_type que no sea MULTIPART_CONTENT - content_type solo se utilizará para descubrir qué juego de caracteres utilizar para codificar esa url- cadena codificada Esto está documentado here. El bit pertinente dice:

Si proporciona content_type (por ejemplo, text/xml para una carga XML), el contenido de los datos serán enviados como está en la solicitud POST, utilizando content_type en el HTTP Content-Type encabezamiento.

Si no proporciona un valor para content_type, los valores de los datos se transmitirán con un tipo de contenido de multipart/form-data. En este caso, los pares clave-valor en datos se codificarán como un mensaje multiparte y se usarán para crear la carga útil de datos POST.

+0

Gracias por la ayuda;) – Andres

0

Pero declarada como una cadena - que tiene comillas simples alrededor del valor de data.

+0

No importa, consulte la segunda forma de enviar datos. Incluso eso se agrupa. – Andres

1

Editar: Y, por supuesto, justo en la línea por encima de la que comencé a mirar es la respuesta correcta. post_data se maneja de forma diferente en función de content_type. Vea la respuesta a continuación. No es necesario aplicar el cambio a continuación.

Parece que lo que sucede es que el dato de datos que ingresa a la publicación se aplana inmediatamente mediante una función de codificación de cadena en una representación de cadena del dict, que el QueryDict más adelante no puede leer. No sé cuál es el comportamiento previsto, pero si urlencode los datos de la publicación antes de que se serialice, al menos debería llegar en el formulario requerido en QueryDict. En Django/test/client.py vemos línea 244

post_data = smart_str(data, encoding=charset) 

que acaba aplana el dict y serializa. Una posible solución sería aplicar el mismo formato que utiliza GET antes de la serialización, por lo tanto,

post_data = smart_str(urlencode(data, doseq=True), encoding=charset) 

Esto me parece razonable, aunque no puedo garantizar que no tiene consecuencias en otros lugares. Parece que podría hacer la transformación anterior en su código antes de la llamada a client.post, pero no lo he probado.

Cuestiones relacionadas