This script is an adaptation from http://www.djangosnippets.org/snippets/678/ . Here, it doesnt use the cache middleware but relies on sessions.
The script set a session cookie to identify the upload and track it to make it available for a progress bar like this one : http://www.djangosnippets.org/snippets/679/ . Note the progress bar cannot work with development server as it is single-threaded. Tested with apache/mod_python and mod_wsgi.
any comments appreciated ;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # views.py
from django.core.files.uploadhandler import FileUploadHandler, UploadFileException
# class who handles the upload
class ProgressUploadHandler(FileUploadHandler):
"""
Download the file and store progression in the session
"""
def __init__(self, request=None, outPath="/tmp"):
super(ProgressUploadHandler, self).__init__(request)
self.progress_id = None
self.cache_key = None
self.request = request
self.outPath = outPath
self.destination = None
def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
self.content_length = content_length
if 'X-Progress-ID' in self.request.GET :
self.progress_id = self.request.GET['X-Progress-ID']
elif 'X-Progress-ID' in self.request.META:
self.progress_id = self.request.META['X-Progress-ID']
if self.progress_id:
self.cache_key = self.progress_id
self.request.session['upload_progress_%s' % self.cache_key] = {
'length': self.content_length,
'uploaded' : 0
}
def new_file(self, field_name, file_name, content_type, content_length, charset=None):
#if not is_valid_upload(file_name): # here you can use a function to filter uploaded files.
# raise UploadFileException , "forbidden file type"
self.outPath = os.path.join(self.outPath, file_name)
self.destination = open(self.outPath, 'wb+')
pass
def receive_data_chunk(self, raw_data, start):
data = self.request.session['upload_progress_%s' % self.cache_key]
data['uploaded'] += self.chunk_size
self.request.session['upload_progress_%s' % self.cache_key] = data
self.request.session.save()
self.destination.write( raw_data)
# data wont be passed to any other handler
return None
def file_complete(self, file_size):
pass
def upload_complete(self):
try:
self.destination.close()
except:
pass
del self.request.session['upload_progress_%s' % self.cache_key]
# view that display the current upload progress (json)
def upload_progress(request):
"""
Return JSON object with information about the progress of an upload.
"""
progress_id = ''
if 'X-Progress-ID' in request.GET:
progress_id = request.GET['X-Progress-ID']
elif 'X-Progress-ID' in request.META:
progress_id = request.META['X-Progress-ID']
if progress_id:
cache_key = "%s" % (progress_id)
data = request.session.get('upload_progress_%s' % cache_key, None)
return HttpResponse(simplejson.dumps(data))
else:
return HttpResponseServerError('Server Error: You must provide X-Progress-ID header or query param.')
# view thath launch the upload process
def upload_form(request):
if request.method == 'POST':
outPath = os.path.join(settings.UPLOAD_ROOT, str(request.user.id)) # set your upload path here
if not os.path.exists(outPath):
os.makedirs(outPath)
request.upload_handlers.insert(0, ProgressUploadHandler(request, outPath)) # place our custom upload in first position
upload_file = request.FILES.get('file', None) # start the upload
return HttpResponse("uploaded ok")
# the html upload form. i use an iframe as target so the page isnt reloaded.
# the upload_form view is used to receive the file
<form name="upload_form" id="upload_form" method="POST" enctype="multipart/form-data"target="VIRTUAL" >
Fichier: <input type="file" name="file" id="id_file" size="45" style=";height:25px;" />
<button id="upload_submit" onclick="doupload()" style="height:25px;padding:1px">
<img src="/media/etiquettes/commons/accept.gif" border="0" /> envoyer</button>
<div id="progress_container" style="display:none;width:300px;border:1px solid red;text-align:left;height:15px">
<div id='progress' style='background:#CCFF99;text-align:center;display:none;padding:5px;width:0%;color:black;font-size:10px;font-weight:bold;'>0%</div>
</div>
<iframe id="VIRTUAL" name="VIRTUAL" style="display:none" width="1" height="1" src="about:blank"></iframe>
</form>
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Can you post a full snippets with the template???
#
Probably a dumb question but what does the doupload() (when you click the button) call? Cos I can't find that call in the ajax script
#
In receive_data_chunk, +chunksize is not correct since the last chunk the real data size may be not chunksize, you should use len(raw_data)
#
In IE 9, I found an issue: the .getJSON request may not be in the same session with the upload file request if you request uploading in the first time. I checked the request.session.session_key, and found they were different. :(.
#
Please login first before commenting.