Ticket #10044: 10044.diff

File 10044.diff, 4.8 KB (added by Marty Alchin, 16 years ago)

Updated FieldFile to accept File objects through attribute assignment, saving them automatically when the associated instance is saved

  • django/db/models/fields/files.py

     
     1import copy
    12import datetime
    23import os
    34
     
    2122        self.storage = field.storage
    2223        self._name = name or u''
    2324        self._closed = False
     25        self._committed = True
    2426
    2527    def __eq__(self, other):
    2628        # Older code may be expecting FileField values to be simple strings.
     
    7981
    8082        # Update the filesize cache
    8183        self._size = len(content)
     84        self._committed = True
    8285
    8386        # Save the object because it has changed, unless save is False
    8487        if save:
     
    100103        # Delete the filesize cache
    101104        if hasattr(self, '_size'):
    102105            del self._size
     106        self._committed = False
    103107
    104108        if save:
    105109            self.instance.save()
     
    110114        # it's attached to in order to work properly, but the only necessary
    111115        # data to be pickled is the file's name itself. Everything else will
    112116        # be restored later, by FileDescriptor below.
    113         return {'_name': self.name, '_closed': False}
     117        return {'_name': self.name, '_closed': False, '_committed': True}
    114118
    115119class FileDescriptor(object):
    116120    def __init__(self, field):
     
    120124        if instance is None:
    121125            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.name(self.owner.__name__))
    122126        file = instance.__dict__[self.field.name]
    123         if not isinstance(file, FieldFile):
     127        if isinstance(file, basestring) or file is None:
    124128            # Create a new instance of FieldFile, based on a given file name
    125129            instance.__dict__[self.field.name] = self.field.attr_class(instance, self.field, file)
    126         elif not hasattr(file, 'field'):
     130        elif isinstance(file, File) and not isinstance(file, FieldFile):
     131            # Other types of files may be assigned as well, but they need to
     132            # have the FieldFile interface added to them
     133            file_copy = copy.copy(file)
     134            file_copy.__class__ = type(file.__class__.__name__,
     135                                       (file.__class__, FieldFile), {})
     136            file_copy.instance = instance
     137            file_copy.field = self.field
     138            file_copy.storage = self.field.storage
     139            file_copy._committed = False
     140            instance.__dict__[self.field.name] = file_copy
     141        elif isinstance(file, FieldFile) and not hasattr(file, 'field'):
    127142            # The FieldFile was pickled, so some attributes need to be reset.
    128143            file.instance = instance
    129144            file.field = self.field
     
    164179            return None
    165180        return unicode(value)
    166181
     182    def pre_save(self, model_instance, add):
     183        "Returns field's value just before saving."
     184        file = super(FileField, self).pre_save(model_instance, add)
     185        if file and not file._committed:
     186            # Commit the file to storage prior to saving the model
     187            file.save(file.name, file, save=False)
     188        return file
     189
    167190    def contribute_to_class(self, cls, name):
    168191        super(FileField, self).contribute_to_class(cls, name)
    169192        setattr(cls, self.name, FileDescriptor(self))
  • django/core/files/base.py

     
    3232        return self.size
    3333
    3434    def _get_name(self):
     35        if not hasattr(self, '_name'):
     36            raise ValueError("This operation requires the file to have a name.")
    3537        return self._name
    3638    name = property(_get_name)
    3739
  • tests/modeltests/files/models.py

     
    99import tempfile
    1010from django.db import models
    1111from django.core.files.base import ContentFile
     12from django.core.files.uploadedfile import SimpleUploadedFile
    1213from django.core.files.storage import FileSystemStorage
    1314from django.core.cache import cache
    1415
     
    5455>>> obj1.normal.read()
    5556'content'
    5657
     58# File objects can be assigned to FileField attributes,  but shouldn't get
     59# committed until the model it's attached to is saved.
     60
     61>>> obj1.normal = SimpleUploadedFile('assignment.txt', 'content')
     62>>> temp_storage.listdir('tests')
     63([], [u'default.txt', u'django_test.txt'])
     64>>> obj1.save()
     65>>> temp_storage.listdir('tests')
     66([], [u'assignment.txt', u'default.txt', u'django_test.txt'])
     67
    5768# Files can be read in a little at a time, if necessary.
    5869
    5970>>> obj1.normal.open()
Back to Top