2010-11-16 20 views
11

Sto tentando di utilizzare il caricamento Ajax di Valum per caricare file su un sito basato su Django- che sto creando. Attualmente sto evitando un modulo semplicemente perché AU invia il caricamento come la totalità dei dati POST in una richiesta ajax . In questo momento ho un approccio molto ingenuo a fare questo:Caricamento di Ajango Ajax al di fuori di un modulo

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

Questo funziona benissimo ... su file di piccole dimensioni. Ho provato con PDF, vari altri file e fino al pacchetto deb di Google Chrome da ~ 20MB e sono tutti in grado di fare ottimi risultati con lo . Tuttavia, se mi sposto in qualcosa come un CD o un DVD iso bombarda in modo orribile. Spesso Django invia una risposta di memoria esaurita . In superficie questo ha senso poiché SimpleUploadedFile è una versione in-memory delle classi di upload. Non riesco a vedere come utilizzare TemporaryUploadedFile perché non accetta il contenuto effettivo nel suo costruttore . Come nota a margine: penserei che dopo aver usato la RAM disponibile su sarebbe andata alla memoria virtuale, ma qualunque cosa.

Quindi, la mia domanda è: come faccio a farlo funzionare? C'è un modo migliore per leggere nel file? Ho provato a leggere direttamente il raw_post_data tramite IO di Python (il sistema utilizza 2.6.5) ma il codificatore/decodificatore ASCII di FileIO si lamenterà ovviamente dei caratteri non ascii quando si lavora con i file binari . Non sono stato in grado di trovare informazioni sulla modifica dell'encoder/decoder .

Non mi dispiacerebbe passare i dati in una forma e con Django fare il lavoro di scegliere la classe di upload a destra e così via, ma non riesco a capire fuori come passare, perché qualcosa di simile

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

non funziona perché il POST contiene il file e non le normali informazioni su Django e FILES non esistono.

Come ho detto, non sono preoccupato per il metodo della soluzione, solo che ottengo qualcosa che funzioni! Grazie!

risposta

9

Bene, ho trovato due soluzioni se qualcuno è interessato.

Il primo è un modo puro in Python di farlo con moderato successo.

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) 

ha funzionato sui test per file di piccole dimensioni (fino a 20 MB), ma non è riuscito quando l'ho provato con le ISO (~ 600MB) o file di dimensioni maggiori. Non ho provato nulla tra il 20MB e il 600MB, quindi non sono sicuro di dove sia il punto di rottura. Ho copiato il fondo della traccia qui sotto, non sono sicuro di quale sia il problema di root in questa situazione. Sembrava esserci una lotta con la memoria, ma avevo abbastanza RAM + swap per contenere il file tre volte, quindi non sono sicuro del perché ci fosse un problema. Non sono sicuro che l'uso di altre forme di lettura/scrittura di Python o di non utilizzo dei buffer possa essere d'aiuto.

[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 soluzione che ha lavorato con tutto quello che ho gettato a lui, fino a 2 GB di file, almeno, necessaria Django 1.3. Hanno aggiunto il supporto di tipo file per la lettura direttamente da HttpRequest, quindi ne ho approfittato.

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

Ho scritto un post sul blog che mostra l'immagine completa su come caricare Ajax su Django 1.3, che include la soluzione di cui sopra. http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html –

+0

Grazie per questo @ alex-kuhl C'è un modo per munge il supporto di tipo file nel ultima versione di Django (1.2.5)? Temo di colpire l'aggiornamento dell'inferno della dipendenza. – michela

+0

Non ho avuto problemi con l'aggiornamento a 1.3, quindi potrebbe non essere così male come pensi. In realtà non ho mai provato a ottenere il supporto di tipo file in 1.2.5, quindi non sono sicuro che sia possibile farlo, sospetto non facilmente. Quello che ho fatto nel primo frammento sopra è stato provare ad usare le normali funzionalità di Python ed evitare Django. Ha funzionato, come ho notato, ma non è riuscito per i file di una certa dimensione. Se non si accettano i file di grandi dimensioni, è possibile utilizzare il codice così com'è, altrimenti sono sicuro che esiste un modo per risolvere il problema in tutti i casi. Potrebbe essere semplice come fare la lettura/scrittura di file usando classi diverse. –

Problemi correlati