# https://github.com/FineUploader/server-examples/blob/master/python/django-fine-uploader from django.conf import settings from django import forms from django.forms import ClearableFileInput import os, os.path import tempfile import shutil __all__ = ( 'handle_upload', 'save_upload', 'FineUploadForm', 'FineUploadFileInput' ) def combine_chunks(total_parts, total_size, source_folder, dest): if not os.path.exists(os.path.dirname(dest)): os.makedirs(os.path.dirname(dest)) with open(dest, 'wb+') as destination: for i in range(total_parts): part = os.path.join(source_folder, str(i)) with open(part, 'rb') as source: destination.write(source.read()) def save_upload(f, path): if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) with open(path, 'wb+') as destination: if hasattr(f, 'multiple_chunks') and f.multiple_chunks(): for chunk in f.chunks(): destination.write(chunk) else: destination.write(f.read()) # pass callback function to post_upload def handle_upload(f, fileattrs, upload_dir, post_upload=None): chunks_dir = os.path.join(tempfile.gettempdir(), 'chunk_upload_tmp') if not os.path.exists(os.path.dirname(chunks_dir)): os.makedirs(os.path.dirname(chunks_dir)) chunked = False dest_folder = upload_dir dest = os.path.join(dest_folder, fileattrs['qqfilename']) # Chunked if fileattrs.get('qqtotalparts') and int(fileattrs['qqtotalparts']) > 1: chunked = True dest_folder = os.path.join(chunks_dir, fileattrs['qquuid']) dest = os.path.join(dest_folder, fileattrs['qqfilename'], str(fileattrs['qqpartindex'])) save_upload(f, dest) # If the last chunk has been sent, combine the parts. if chunked and (fileattrs['qqtotalparts'] - 1 == fileattrs['qqpartindex']): combine_chunks(fileattrs['qqtotalparts'], fileattrs['qqtotalfilesize'], source_folder=os.path.dirname(dest), dest=os.path.join(upload_dir, fileattrs['qqfilename'])) shutil.rmtree(os.path.dirname(os.path.dirname(dest))) if post_upload and (not chunked or fileattrs['qqtotalparts'] - 1 == fileattrs['qqpartindex']): post_upload() class FineUploadForm(forms.Form): qqfile = forms.FileField() qquuid = forms.CharField() qqfilename = forms.CharField() qqpartindex = forms.IntegerField(required=False) qqchunksize = forms.IntegerField(required=False) qqpartbyteoffset = forms.IntegerField(required=False) qqtotalfilesize = forms.IntegerField(required=False) qqtotalparts = forms.IntegerField(required=False) class FineUploadFileInput(ClearableFileInput): template_name = 'widgets/fine_uploader.html' def fine_uploader_id(self, name): return name + '_' + 'fine_uploader' def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) context['widget'].update({ 'fine_uploader_id': self.fine_uploader_id(name), }) return context