2010-11-16 12 views
11

Estoy tratando de usar la carga de Ajax de Valum para cargar archivos en un sitio basado en Django- que estoy creando. Actualmente estoy evitando un formulario simplemente porque AU envía la carga como la totalidad de los datos POST en una solicitud ajax . En este momento tengo un enfoque muy ingenuo para hacer esto:Subida de Djago Ajax fuera de un formulario

upload = SimpleUploadedFile(filename, request.raw_post_data) 
...then I loop through the chunks to write to disk... 

Esto funciona muy bien ... en archivos pequeños. He probado con archivos PDF, varios archivos y hasta el paquete de Deb de 20MB de Google Chrome, y todos ellos son geniales . Sin embargo, si paso a algo así como un CD o DVD iso , se bombardea horriblemente. A menudo, Django devuelve una respuesta de memoria insuficiente . En la superficie esto tiene sentido ya que SimpleUploadedFile es una versión en la memoria de las clases de carga. No puedo ver cómo usar TemporaryUploadedFile porque no toma el contenido real en su constructor . Como nota al margen: yo pensaría que después de usar la RAM disponible iría a la memoria virtual, pero lo que sea.

Entonces, mi pregunta es, ¿cómo hago para que funcione? ¿Hay una mejor manera de leer en el archivo? Intenté leer el raw_post_data directamente a través de Python's IO (el sistema usa 2.6.5) pero el codificador/decodificador ascii de FileIO obviamente se quejará de caracteres no ascii cuando se trabaja con los archivos binarios . No he podido encontrar información sobre cómo cambiar el codificador/decodificador .

no me importaría pasar los datos en un formulario y tener Django hacer la trabajo de escoger la clase de carga derecha y así sucesivamente, pero no puedo imaginar cómo pasar porque algo así como

upload_form = UploadForm(request.POST, request.FILES) 

no funcionará porque la POST contiene el archivo y no la información normal de Django y los ARCHIVOS no existen.

Como dije, no estoy preocupado por el método de la solución, solo que ¡Obtengo algo que funciona! ¡Gracias!

Respuesta

9

Bueno, encontré dos soluciones si alguien está interesado.

La primera es una forma pura de Python de hacerlo moderadamente exitosa.

with BufferedReader(BytesIO(request.raw_post_data)) as stream: 
    with BufferedWriter(FileIO("/tmp/foo.bar", "wb")) as destination: 
    foo = stream.read(1024) 
    while foo: 
     destination.write(foo) 
     foo = stream.read(1024) 

Se trabajó en las pruebas para archivos pequeños (hasta 20 MB), pero falló cuando lo probé con ISO (~ 600 MB) o archivos de mayor tamaño. No intenté nada entre los 20 MB y los 600 MB, así que no estoy seguro de dónde está el punto de quiebre. He copiado la parte inferior de la siguiente pista, no estoy seguro de cuál es el problema de raíz en esta situación. Parecía haber una lucha con la memoria, pero tenía suficiente RAM + intercambio para mantener el archivo tres veces, por lo que no estaba seguro de por qué había un problema. No estoy seguro si el uso de otras formas de lectura/escritura de Python o el uso de almacenamientos intermedios ayudaría aquí.

[error] [client 127.0.0.1] File "/usr/local/lib/python2.6 /dist-packages/django/core/handlers/wsgi.py", line 69, in safe_copyfileobj, referer: http://localhost/project/ 
[error] [client 127.0.0.1]  buf = fsrc.read(min(length, size)), referer: http://localhost/project/ 
[error] [client 127.0.0.1] TemplateSyntaxError: Caught IOError while rendering: request data read error, referer: http://localhost/project/ 

La solución que ha trabajado con todo lo que he echado en ella, hasta 2 GB de archivos, al menos, se requiere Django 1.3. Han agregado soporte similar a un archivo para leer directamente desde HttpRequest, así que aproveché eso.

with BufferedWriter(FileIO("/tmp/foo.bar", "wb")) as destination: 
    foo = request.read(1024) 
    while foo: 
    destination.write(foo) 
    foo = request.read(1024) 
+0

Escribí una publicación de blog que muestra la imagen completa para que Ajax Upload trabaje con Django 1.3, que incluye la solución anterior. http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html –

+0

Gracias por esto @ alex-kuhl ¿Hay alguna forma de enviar el soporte similar a un archivo al última versión de Django (1.2.5)? Me temo que voy a golpear la actualización infernal de la dependencia. – michela

+0

No tuve ningún problema para actualizar a 1.3, por lo que puede no ser tan malo como crees. En realidad, nunca intenté obtener soporte para archivos en 1.2.5, así que no estoy seguro de si se puede hacer eso, sospecho que no es fácil. Lo que hice en el primer fragmento de arriba fue tratar de usar la funcionalidad regular de Python y evitar Django. Funcionó, como noté, pero falló para archivos de un cierto tamaño. Si no permite archivos grandes, puede usar el código tal como está; de lo contrario, estoy seguro de que hay una forma de solucionarlo para que funcione en todos los casos. Podría ser tan simple como hacer el archivo de lectura/escritura usando diferentes clases. –

Cuestiones relacionadas