Skip to content

Instantly share code, notes, and snippets.

@lyhapple
Last active August 29, 2015 14:20
Show Gist options
  • Save lyhapple/657ca6fe04bdc0ed5491 to your computer and use it in GitHub Desktop.
Save lyhapple/657ca6fe04bdc0ed5491 to your computer and use it in GitHub Desktop.
python ajax upload
class LocalUploadBackend(object):
BUFFER_SIZE = 10485760 # 10MB
def __init__(self,path,ext= '.bak'):
self.path = path
self.extension = ext
self.md5sum = None
def setup(self, filename):
utils.ensure_fold(self.path)
filename_no_extension, _ = os.path.splitext(filename)
self._dest = BufferedWriter(FileIO(self.path+'/'+
filename_no_extension+self.extension, "w"))
def upload_chunk(self, chunk):
self._dest.write(chunk)
def upload_complete(self, request, filename):
self._dest.close()
#TODO detect iso
return {"path": self.path+'/'+filename}
def upload(self, uploaded, raw_data):
try:
if raw_data:
# File was uploaded via ajax, and is streaming in.
chunk = uploaded.read(self.BUFFER_SIZE)
while len(chunk) > 0:
self.upload_chunk(chunk)
chunk = uploaded.read(self.BUFFER_SIZE)
else:
# File was uploaded via a POST, and is here.
md5 = hashlib.md5()
for chunk in uploaded.chunks():
self.upload_chunk(chunk)
md5.update(chunk)
self.md5sum = md5.hexdigest()
return True, self.md5sum
except:
# things went badly.
return False
def add_ext(self, file_name):
return file_name+self.extension
def update_filename(self, filename,add_ext=True):
"""
Returns a new name for the file being uploaded.
Ensure file with name doesn't exist, and if it does,
create a unique filename to avoid overwriting
"""
self._dir = self.path
unique_filename = False
filename_suffix = 0
filename = filename.encode('utf-8')
# Check if file at filename exists
if os.path.isfile(os.path.join(self._dir, filename)):
while not unique_filename:
try:
filename_no_extension, _ = os.path.splitext(filename)
if filename_suffix == 0:
open(os.path.join(self._dir, self.add_ext(filename) if add_ext else filename))
else:
tmpfile_name = filename + str(filename_suffix)
open(os.path.join(self._dir, self.add_ext(tmpfile_name) if add_ext else tmpfile_name))
filename_suffix += 1
except IOError:
unique_filename = True
if filename_suffix == 0:
return filename
else:
return filename_no_extension + str(filename_suffix) + self.extension
class AjaxFileUploader(object):
def __init__(self, **kwargs):
path = kwargs.get('path',"/tmp")
self.backend = LocalUploadBackend(path)
def __call__(self,request):
return self._ajax_upload(request)
def _ajax_upload(self, request):
if request.method == "POST":
if request.is_ajax():
# the file is stored raw in the request
upload = request
is_raw = True
# AJAX Upload will pass the filename in the querystring if it
# is the "advanced" ajax upload
try:
filename = request.GET['filename']
except KeyError:
raise exception.BadInputError()
# not an ajax upload, so it was the "basic" iframe version with
# submission via form
else:
is_raw = False
if len(request.FILES) == 1:
upload = request.FILES.values()[0]
else:
raise Http404("Bad Upload")
filename = upload.name
# custom filename handler
filename = (self.backend.update_filename(filename)
or filename)
# save the file
self.backend.setup(filename)
success,_ = self.backend.upload(upload, filename, is_raw)
# callback
extra_context = self.backend.upload_complete(request, filename)
# let Ajax Upload know whether we saved it or not
ret_json = {'success': success, 'filename': filename}
if extra_context is not None:
ret_json.update(extra_context)
return ret_json
# usage:
ajax = AjaxFileUploader()
ret = ajax(request)
if ret['success']:
pass #do somthing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment