Last active
August 29, 2015 14:20
-
-
Save lyhapple/657ca6fe04bdc0ed5491 to your computer and use it in GitHub Desktop.
python ajax upload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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