2010-11-16 14 views
11

Yaptığım bir Django- tabanlı sitede dosya yüklemeleri yapmak için Valum'un Ajax Yükleme'yi kullanmaya çalışıyorum. Şu anda bir formdan kaçınmaktayım çünkü AU, yüklemeyi bir ajax isteğinde POST verilerinin tamamı olarak gönderir. Şu anda bunu yapmak için çok saf bir yaklaşımım var:Django Ajax Bir Form Dışı Yükleme

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

Bu küçük dosyalar üzerinde harika çalışıyor. PDF'lerle, çeşitli diğer dosyalarla ve ~ 20MB Google Chrome deb paketine kadar test ettim ve hepsi harika. Bununla birlikte, CD veya DVD iso gibi bir şeye geçersem, korkunç bir şekilde bombalar. Sık sık Django, bir Bellek Dolu yanıtı geri gönderir. Yüzeyde, SimpleUploadedFile, yükleme sınıflarının bir bellek içi sürümü olan olduğundan bu anlamlıdır. yapıcısında gerçek içeriği almadığı için TemporaryUploadedFile öğesinin nasıl kullanıldığını göremiyorum. Bir yan not olarak: Ben kullanılabilir RAM kullandıktan sonra düşünürdüm, sanal belleğe gider, ama her neyse.

Yani, sorum şu, işe nasıl başlarım? Dosyada okumak için daha iyi bir yolu var mı? Python'un IO'sunu (sistem 2.6.5'i kullanır) kullanarak raw_post_data'yı doğrudan okumayı denedim, ancak ikili dosyaları ile çalışırken FileIO'nun ascii encoder/decoder açıkçası ascii olmayan karakterler hakkında şikayette bulunacaktır. kodlayıcı/kod çözücüyü değiştirmeyle ilgili bilgileri bulamadım.

bir forma veri geçirerek ve Django benzeri Doğru yükleme sınıfını toplama ve işi yapmak zorunda sakıncası olmaz, ama bunu nasıl geçirileceği bilemiyorum

çünkü

upload_form = UploadForm(request.POST, request.FILES) 
gibi bir şey

, POST dosyayı içerdiğinden ve normal Django bilgisi değil ve FILES bulunmadığından çalışmayacaktır.

Dediğim gibi, çözüm yönteminden endişelenmiyorum, sadece bu Çalıştığım bir şey buluyorum! Teşekkürler!

cevap

9

Ben ilgilenen varsa iki çözüm buldum.

Birincisi, orta derecede başarılı olan saf Python yöntemidir.

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) 

Küçük dosyalar için test (20MB kadar) üzerinde çalıştı ama ISO'lara (~ 600MB) veya daha büyük dosyalar ile çalıştığımızda başarısız oldu. 20MB ve 600MB arasında hiçbir şey denemedim, bu yüzden kırılma noktasının nerede olduğundan emin değilim. İzin altını kopyaladım, bu durumda kök sorunun ne olduğundan emin değilim. Bellek ile bir mücadele var gibi görünüyordu, ama ben dosyayı üç kez tutmak için yeterli RAM + takas vardı, bu yüzden bir sorun vardı emin değilim. Python'un okuma/yazma ile ilgili diğer formlarını kullanıp kullanmadığına veya tampon kullanmayacağınıza emin olamayacağınızdan emin olabilirsiniz.

[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/ 

En azından 2GB dosyasına kadar, ona atılan her şeyle çalıştı çözüm Django 1.3 gereklidir. HttpRequest'ten doğrudan okumak için dosyaya benzer bir destek eklediler, bundan faydalandım.

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

Ajax Upload'un Django 1 ile çalışmasını sağlayarak tam resmi gösteren bir blog yazısı yazdım.Yukarıdaki çözümü içeren 3. http://kuhlit.blogspot.com/2010/12/ajax-uploads-in-django-with-little-help.html –

+0

Bu @ alex-kuhl için teşekkürler Dosyaya benzer desteği içine sokmanın bir yolu var mı Django'nun son sürümü (1.2.5)? Korkarım bağımlılığı cehenneme yükselteceğim. – michela

+0

1.3'e yükseltme yapmakta herhangi bir sorun yaşamadım, bu yüzden düşündüğünüz kadar kötü olmayabilir. Ben asla 1.2.5'te dosyaya benzer bir destek almayı denemedim, bu yüzden yapılıp yapılamayacağından emin değilim, kolay bir şekilde şüpheleniyorum. Yukarıdaki ilk snippet'te yaptığım şey, düzenli Python işlevselliğini kullanmaya ve Django'dan kaçınmaya çalışmaktı. Benim de söylediğim gibi işe yaradı, ancak belli bir boyuttaki dosyalar için başarısız oldu. Büyük dosyalara izin vermezseniz, kodu olduğu gibi kullanabilirsiniz. Aksi halde, tüm vakalarda çalışmak için bunu düzeltmenin bir yolu olduğundan eminim. Farklı sınıflar kullanarak dosya okuma/yazma yapmak kadar basit olabilir. –