Django

Code

Ticket #2070: 2070_revision7339_formhandling.diff

File 2070_revision7339_formhandling.diff, 11.4 kB (added by axiak, 4 months ago)

NEW Form handling for uploaded files for revision 7339

  • django/oldforms/__init__.py

    old new  
    680680        self.field_name, self.is_required = field_name, is_required 
    681681        self.validator_list = [self.isNonEmptyFile] + validator_list 
    682682 
    683     def isNonEmptyFile(self, field_data, all_data): 
    684         try
    685             content = field_data['content'] 
    686         except TypeError
    687             raise validators.CriticalValidationError, ugettext("No file was submitted. Check the encoding type on the form.") 
    688         if not content
     683    def isNonEmptyFile(self, new_data, all_data): 
     684        if hasattr(new_data, 'upload_errors')
     685            upload_errors = new_data.upload_errors() 
     686            if upload_errors
     687                raise validators.CriticalValidationError, upload_errors 
     688        if not new_data.file_size
    689689            raise validators.CriticalValidationError, ugettext("The submitted file is empty.") 
    690690 
    691691    def render(self, data): 
    692692        return mark_safe(u'<input type="file" id="%s" class="v%s" name="%s" />' % \ 
    693693            (self.get_id(), self.__class__.__name__, self.field_name)) 
    694694 
     695    def prepare(self, new_data): 
     696        if hasattr(new_data, 'upload_errors'): 
     697            upload_errors = new_data.upload_errors() 
     698            new_data[self.field_name] = { '_file_upload_error': upload_errors } 
     699 
    695700    def html2python(data): 
    696701        if data is None: 
    697702            raise EmptyValue 
  • django/db/models/base.py

    old new  
    1313from django.utils.datastructures import SortedDict 
    1414from django.utils.functional import curry 
    1515from django.utils.encoding import smart_str, force_unicode, smart_unicode 
     16from django.core.files.filemove import file_move_safe 
    1617from django.conf import settings 
    1718from itertools import izip 
    1819import types 
     
    384385    def _get_FIELD_size(self, field): 
    385386        return os.path.getsize(self._get_FIELD_filename(field)) 
    386387 
    387     def _save_FIELD_file(self, field, filename, raw_contents, save=True): 
     388    def _save_FIELD_file(self, field, filename, raw_field, save=True): 
    388389        directory = field.get_directory_name() 
    389390        try: # Create the date-based directory if it doesn't exist. 
    390391            os.makedirs(os.path.join(settings.MEDIA_ROOT, directory)) 
    391392        except OSError: # Directory probably already exists. 
    392393            pass 
     394 
     395        if filename is None: 
     396            filename = raw_field.file_name 
     397 
    393398        filename = field.get_filename(filename) 
    394399 
    395400        # If the filename already exists, keep adding an underscore to the name of 
     
    406411        setattr(self, field.attname, filename) 
    407412 
    408413        full_filename = self._get_FIELD_filename(field) 
    409         fp = open(full_filename, 'wb') 
    410         fp.write(raw_contents) 
    411         fp.close() 
     414        if hasattr(raw_field, 'temporary_file_path'): 
     415            raw_field.close() 
     416            file_move_safe(raw_field.temporary_file_path(), full_filename) 
     417        else: 
     418            from django.utils import file_locks 
     419            fp = open(full_filename, 'wb') 
     420            # exclusive lock 
     421            file_locks.lock(fp, file_locks.LOCK_EX) 
     422            # Stream it into the file, from where it is. 
     423            for chunk in raw_field.chunk(65535): 
     424                fp.write(chunk) 
     425            fp.close() 
    412426 
    413427        # Save the width and/or height, if applicable. 
    414428        if isinstance(field, ImageField) and (field.width_field or field.height_field): 
  • django/db/models/fields/__init__.py

    old new  
    785785        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self)) 
    786786        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self)) 
    787787        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self)) 
    788         setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save)) 
     788        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save)) 
     789        setattr(cls, 'move_%s_file' % self.name, lambda instance, raw_field, save=True: instance._save_FIELD_file(self, None, raw_field, save)) 
    789790        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls) 
    790791 
    791792    def delete_file(self, instance): 
     
    808809        if new_data.get(upload_field_name, False): 
    809810            func = getattr(new_object, 'save_%s_file' % self.name) 
    810811            if rel: 
    811                 func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save) 
     812                func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0], save) 
    812813            else: 
    813                 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save) 
     814                func(new_data[upload_field_name]["filename"], new_data[upload_field_name], save) 
    814815 
    815816    def get_directory_name(self): 
    816817        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to)))) 
     
    823824    def save_form_data(self, instance, data): 
    824825        from django.newforms.fields import UploadedFile 
    825826        if data and isinstance(data, UploadedFile): 
    826             getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False) 
     827            getattr(instance, "save_%s_file" % self.name)(data.filename, data.data, save=False) 
    827828 
    828829    def formfield(self, **kwargs): 
    829830        defaults = {'form_class': forms.FileField} 
  • django/core/files/filelocks.py

    old new  
     1""" 
     2Locking portability by Jonathan Feignberg <jdf@pobox.com> in python cookbook 
     3 
     4Example Usage:: 
     5 
     6    from django.utils import file_locks 
     7 
     8    f = open('./file', 'wb') 
     9 
     10    file_locks.lock(f, file_locks.LOCK_EX) 
     11    f.write('Django') 
     12    f.close() 
     13""" 
     14 
     15 
     16import os 
     17 
     18__all__ = ['LOCK_EX','LOCK_SH','LOCK_NB','lock','unlock'] 
     19 
     20if os.name == 'nt': 
     21        import win32con 
     22        import win32file 
     23        import pywintypes 
     24        LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK 
     25        LOCK_SH = 0 
     26        LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY 
     27        __overlapped = pywintypes.OVERLAPPED() 
     28elif os.name == 'posix': 
     29        import fcntl 
     30        LOCK_EX = fcntl.LOCK_EX 
     31        LOCK_SH = fcntl.LOCK_SH 
     32        LOCK_NB = fcntl.LOCK_NB 
     33else: 
     34        raise RuntimeError("Locking only defined for nt and posix platforms") 
     35 
     36if os.name == 'nt': 
     37        def lock(file, flags): 
     38                hfile = win32file._get_osfhandle(file.fileno()) 
     39                win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped) 
     40 
     41        def unlock(file): 
     42                hfile = win32file._get_osfhandle(file.fileno()) 
     43                win32file.UnlockFileEx(hfile, 0, -0x10000, __overlapped) 
     44 
     45elif os.name =='posix': 
     46        def lock(file, flags): 
     47                fcntl.flock(file.fileno(), flags) 
     48 
     49        def unlock(file): 
     50                fcntl.flock(file.fileno(), fcntl.LOCK_UN) 
  • django/core/files/filemove.py

    old new  
     1import os 
     2 
     3__all__ = ('file_move_safe',) 
     4 
     5try: 
     6    import shutil 
     7    file_move = shutil.move 
     8except ImportError: 
     9    file_move = os.rename 
     10 
     11def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_overwrite=False): 
     12    """ 
     13    Moves a file from one location to another in the safest way possible. 
     14     
     15    First, it tries using shutils.move, which is OS-dependent but doesn't 
     16    break with change of filesystems. Then it tries os.rename, which will 
     17    break if it encounters a change in filesystems. Lastly, it streams 
     18    it manually from one file to another in python. 
     19 
     20    Without ``allow_overwrite``, if the destination file exists, the 
     21    file will raise an IOError. 
     22    """ 
     23 
     24    from django.core.files import filelocks 
     25 
     26    if old_file_name == new_file_name: 
     27        # No file moving takes place. 
     28        return 
     29 
     30    if not allow_overwrite and os.path.exists(new_file_name): 
     31        raise IOError, "Django does not allow overwriting files." 
     32 
     33    try: 
     34        file_move(old_file_name, new_file_name) 
     35        return 
     36    except OSError: # moving to another filesystem 
     37        pass 
     38 
     39    new_file = open(new_file_name, 'wb') 
     40    # exclusive lock 
     41    filelocks.lock(new_file, filelocks.LOCK_EX) 
     42    old_file = open(old_file_name, 'rb') 
     43    current_chunk = None 
     44 
     45    while current_chunk != '': 
     46        current_chunk = old_file.read(chunk_size) 
     47        new_file.write(current_chunk) 
     48 
     49    new_file.close() 
     50    old_file.close() 
     51 
     52    os.remove(old_file_name) 
     53 
  • django/newforms/fields.py

    old new  
    416416 
    417417class UploadedFile(StrAndUnicode): 
    418418    "A wrapper for files uploaded in a FileField" 
    419     def __init__(self, filename, content): 
     419    def __init__(self, filename, data): 
    420420        self.filename = filename 
    421         self.content = content 
     421        self.data = data 
    422422 
    423423    def __unicode__(self): 
    424424        """ 
     
    445445        elif not data and initial: 
    446446            return initial 
    447447        try: 
    448             f = UploadedFile(data['filename'], data['content']
     448            f = UploadedFile(data['filename'], data
    449449        except TypeError: 
    450450            raise ValidationError(self.error_messages['invalid']) 
    451451        except KeyError: 
    452452            raise ValidationError(self.error_messages['missing']) 
    453         if not f.content
     453        if not f.data.file_size
    454454            raise ValidationError(self.error_messages['empty']) 
    455455        return f 
    456456 
     
    470470        elif not data and initial: 
    471471            return initial 
    472472        from PIL import Image 
    473         from cStringIO import StringIO 
     473 
     474        # We need to get the file, it either has a path 
     475        # or we have to read it all into memory... 
     476        if hasattr(data, 'temporary_file_path'): 
     477            file = data.temporary_file_path() 
     478        else: 
     479            try: 
     480                from cStringIO import StringIO 
     481            except ImportError: 
     482                from StringIO import StringIO 
     483            file = StringIO(data.read()) 
     484 
    474485        try: 
    475486            # load() is the only method that can spot a truncated JPEG, 
    476487            #  but it cannot be called sanely after verify() 
    477             trial_image = Image.open(StringIO(f.content)
     488            trial_image = Image.open(file
    478489            trial_image.load() 
    479490            # verify() is the only method that can spot a corrupt PNG, 
    480491            #  but it must be called immediately after the constructor 
    481             trial_image = Image.open(StringIO(f.content)
     492            trial_image = Image.open(file
    482493            trial_image.verify() 
    483494        except Exception: # Python Imaging Library doesn't recognize it as an image 
    484495            raise ValidationError(self.error_messages['invalid_image'])