Ticket #5361: filestorage.6.diff

File filestorage.6.diff, 33.2 KB (added by javinievas, 12 years ago)

Fixed a bug when saving the uploaded file

  • django/core/filestorage/base.py

     
     1from StringIO import StringIO
     2
     3class Backend(object):
     4    def get_available_filename(self, filename):
     5        # If the filename already exists, keep adding an underscore to the name
     6        # of the file until the filename doesn't exist.
     7        while self.file_exists(filename):
     8            try:
     9                dot_index = filename.rindex('.')
     10            except ValueError: # filename has no dot
     11                filename += '_'
     12            else:
     13                filename = filename[:dot_index] + '_' + filename[dot_index:]
     14        return filename
     15
     16    def get_absolute_filename(self, filename):
     17        return None
     18
     19class RemoteFile(StringIO):
     20    """Sends files to a remote backend automatically, when necessary."""
     21
     22    def __init__(self, data, mode, writer):
     23        self._mode = mode
     24        self._write_to_backend = writer
     25        self._is_dirty = False
     26        StringIO.__init__(self, data)
     27
     28    def write(self, data):
     29        if 'w' not in self._mode:
     30            raise AttributeError, "File was opened for read-only access."
     31        StringIO.write(self, data)
     32        self._is_dirty = True
     33
     34    def close(self):
     35        if self._is_dirty:
     36            self._write_to_backend(self.getvalue())
     37        StringIO.close(self)
     38
  • django/core/filestorage/filesystem.py

     
     1import datetime
     2import os
     3
     4from django.conf import settings
     5from django.utils.encoding import force_unicode, smart_str
     6
     7from django.core.filestorage.base import Backend
     8
     9class FileSystemBackend(Backend):
     10    """Standard filesystem storage"""
     11
     12    def __init__(self, location='', media_root=None, media_url=None):
     13        self.location = location
     14        if media_root != None and media_url != None:
     15            # Both were provided, so use them
     16            pass
     17        elif media_root is None and media_url is None:
     18            # Neither were provided, so use global settings
     19            from django.conf import settings
     20            try:
     21                media_root = settings.MEDIA_ROOT
     22                media_url = settings.MEDIA_URL
     23            except AttributeError:
     24                raise ImproperlyConfigured, "Media settings not defined."
     25        else:
     26            # One or the other were provided, but not both
     27            raise ImproperlyConfigured, "Both media_root and media_url must be provided."
     28        self.media_root = media_root
     29        self.media_url = media_url
     30
     31    def _get_directory_name(self):
     32        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.location))))
     33
     34    # The following methods define the Backend API
     35
     36    def get_absolute_path(self, filename):
     37        return os.path.normpath(os.path.join(self.media_root, filename))
     38
     39    def get_available_filename(self, filename):
     40        from django.utils.text import get_valid_filename
     41        f = os.path.join(self._get_directory_name(), get_valid_filename(os.path.basename(filename)))
     42        return Backend.get_available_filename(self, os.path.normpath(f))
     43
     44    def get_filesize(self, filename):
     45        return os.path.getsize(self.get_absolute_path(filename))
     46
     47    def get_absolute_url(self, filename):
     48        import urlparse
     49        return urlparse.urljoin(self.media_url, filename).replace('\\', '/')
     50
     51    def open(self, filename, mode='rb'):
     52        return open(self.get_absolute_path(filename), mode)
     53
     54    def file_exists(self, filename):
     55        return os.path.exists(self.get_absolute_path(filename))
     56
     57    def save_file(self, filename, raw_contents):
     58        directory = self._get_directory_name()
     59        try: # Create the date-based directory if it doesn't exist.
     60            os.makedirs(os.path.join(self.media_root, directory))
     61        except OSError: # Directory probably already exists.
     62            pass
     63        filename = self.get_available_filename(filename)
     64
     65        # Write the file to disk.
     66        fp = open(self.get_absolute_path(filename), 'wb')
     67        fp.write(raw_contents)
     68        fp.close()
     69
     70        return filename
     71
     72    def delete_file(self, filename):
     73        file_name = self.get_absolute_path(filename)
     74        # If the file exists, delete it from the filesystem.
     75        if os.path.exists(file_name):
     76            os.remove(file_name)
  • django/db/models/base.py

     
    1818import types
    1919import sys
    2020import os
     21from warnings import warn
    2122
    2223class ModelBase(type):
    2324    "Metaclass for all models"
     
    366367        return getattr(self, cachename)
    367368
    368369    def _get_FIELD_filename(self, field):
    369         if getattr(self, field.attname): # value is not blank
    370             return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
    371         return ''
     370        warn("Use instance.%s.get_absolute_path()." % field.attname, DeprecationWarning)
     371        return getattr(self, field.attname).get_absolute_path()
    372372
    373373    def _get_FIELD_url(self, field):
    374         if getattr(self, field.attname): # value is not blank
    375             import urlparse
    376             return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
    377         return ''
     374        warn("Use instance.%s.get_absolute_url()." % field.attname, DeprecationWarning)
     375        return getattr(self, field.attname).get_absolute_url()
    378376
    379377    def _get_FIELD_size(self, field):
    380         return os.path.getsize(self._get_FIELD_filename(field))
     378        warn("Use instance.%s.get_filesize()." % field.attname, DeprecationWarning)
     379        return getattr(self, field.attname).get_filesize()
    381380
    382381    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
    383         directory = field.get_directory_name()
    384         try: # Create the date-based directory if it doesn't exist.
    385             os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
    386         except OSError: # Directory probably already exists.
    387             pass
    388         filename = field.get_filename(filename)
     382        warn("Use instance.%s.save_file()." % field.attname, DeprecationWarning)
     383        return getattr(self, field.attname).save_file(filename, raw_contents, save)
    389384
    390         # If the filename already exists, keep adding an underscore to the name of
    391         # the file until the filename doesn't exist.
    392         while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
    393             try:
    394                 dot_index = filename.rindex('.')
    395             except ValueError: # filename has no dot
    396                 filename += '_'
    397             else:
    398                 filename = filename[:dot_index] + '_' + filename[dot_index:]
    399 
    400         # Write the file to disk.
    401         setattr(self, field.attname, filename)
    402 
    403         full_filename = self._get_FIELD_filename(field)
    404         fp = open(full_filename, 'wb')
    405         fp.write(raw_contents)
    406         fp.close()
    407 
    408         # Save the width and/or height, if applicable.
    409         if isinstance(field, ImageField) and (field.width_field or field.height_field):
    410             from django.utils.images import get_image_dimensions
    411             width, height = get_image_dimensions(full_filename)
    412             if field.width_field:
    413                 setattr(self, field.width_field, width)
    414             if field.height_field:
    415                 setattr(self, field.height_field, height)
    416 
    417         # Save the object because it has changed unless save is False
    418         if save:
    419             self.save()
    420 
    421     _save_FIELD_file.alters_data = True
    422 
    423385    def _get_FIELD_width(self, field):
    424         return self._get_image_dimensions(field)[0]
     386        warn("Use instance.%s.get_width()." % field.attname, DeprecationWarning)
     387        return getattr(self, field.attname).get_width()
    425388
    426389    def _get_FIELD_height(self, field):
    427         return self._get_image_dimensions(field)[1]
     390        warn("Use instance.%s.get_height()." % field.attname, DeprecationWarning)
     391        return getattr(self, field.attname).get_height()
    428392
    429     def _get_image_dimensions(self, field):
    430         cachename = "__%s_dimensions_cache" % field.name
    431         if not hasattr(self, cachename):
    432             from django.utils.images import get_image_dimensions
    433             filename = self._get_FIELD_filename(field)
    434             setattr(self, cachename, get_image_dimensions(filename))
    435         return getattr(self, cachename)
    436 
    437393############################################
    438394# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
    439395############################################
  • django/db/models/fields/__init__.py

     
    704704        defaults.update(kwargs)
    705705        return super(EmailField, self).formfield(**defaults)
    706706
     707class File(object):
     708    def __init__(self, obj, field, filename):
     709        self.obj = obj
     710        self.field = field
     711        self.backend = field.backend
     712        self.filename = filename
     713
     714    def __str__(self):
     715        return self.filename
     716
     717    def get_absolute_path(self):
     718        return self.backend.get_absolute_path(self.filename)
     719
     720    def get_absolute_url(self):
     721        return self.backend.get_absolute_url(self.filename)
     722
     723    def get_filesize(self):
     724        if not hasattr(self, '_filesize'):
     725            self._filesize = self.backend.get_filesize(self.filename)
     726        return self._filesize
     727
     728    def open(self, mode='rb'):
     729        return self.backend.open(self.filename, mode)
     730
     731    def save_file(self, filename, raw_contents, save=True):
     732        self.filename = self.backend.save_file(filename, raw_contents)
     733
     734        # Update the filesize cache
     735        self._filesize = len(raw_contents)
     736
     737        # Save the object because it has changed, unless save is False
     738        if save:
     739            self.obj.save()
     740
     741class FileProxy(object):
     742    def __init__(self, field):
     743        self.field = field
     744        self.cache_name = self.field.get_cache_name()
     745
     746    def __get__(self, instance=None, owner=None):
     747        if instance is None:
     748            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.attname, self.owner.__name__)
     749        return getattr(instance, self.cache_name)
     750
     751    def __set__(self, instance, value):
     752        if hasattr(instance, self.cache_name):
     753            raise AttributeError, "%s can not be set in this manner." % self.field.attname
     754        instance.__dict__[self.field.attname] = value
     755        attr = self.field.attr_class(instance, self.field, value)
     756        setattr(instance, self.cache_name, attr)
     757
    707758class FileField(Field):
    708     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
    709         self.upload_to = upload_to
     759    attr_class = File
     760
     761    def __init__(self, verbose_name=None, name=None, upload_to='', backend=None, **kwargs):
     762        if backend is None:
     763            from django.core.filestorage.filesystem import FileSystemBackend
     764            backend = FileSystemBackend(location=upload_to)
     765        self.backend = self.upload_to = backend
    710766        Field.__init__(self, verbose_name, name, **kwargs)
    711767
    712768    def get_db_prep_save(self, value):
     
    714770        # Need to convert UploadedFile objects provided via a form to unicode for database insertion
    715771        if value is None:
    716772            return None
    717         return unicode(value)
     773        return unicode(value.filename)
    718774
    719775    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    720776        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     
    754810
    755811    def contribute_to_class(self, cls, name):
    756812        super(FileField, self).contribute_to_class(cls, name)
     813        setattr(cls, self.attname, FileProxy(self))
    757814        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
    758815        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    759816        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    760817        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))
    761818        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
    762819
    763     def delete_file(self, instance):
    764         if getattr(instance, self.attname):
    765             file_name = getattr(instance, 'get_%s_filename' % self.name)()
    766             # If the file exists and no other object of this type references it,
    767             # delete it from the filesystem.
    768             if os.path.exists(file_name) and \
    769                 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
    770                 os.remove(file_name)
     820    def delete_file(self, instance, sender):
     821        filename = getattr(instance, self.attname).filename
     822        # If no other object of this type references the file,
     823        # delete it from the backend.
     824        if not sender._default_manager.filter(**{self.name: filename}):
     825            self.backend.delete_file(filename)
    771826
    772827    def get_manipulator_field_objs(self):
    773828        return [oldforms.FileUploadField, oldforms.HiddenField]
     
    778833    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    779834        upload_field_name = self.get_manipulator_field_names('')[0]
    780835        if new_data.get(upload_field_name, False):
    781             func = getattr(new_object, 'save_%s_file' % self.name)
    782836            if rel:
    783                 func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)
     837                field = new_data[upload_field_name][0]
    784838            else:
    785                 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
     839                field = new_data[upload_field_name]
     840            getattr(new_object, self.attname).save_file(field["filename"], field["content"], save)
    786841
    787     def get_directory_name(self):
    788         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    789 
    790     def get_filename(self, filename):
    791         from django.utils.text import get_valid_filename
    792         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    793         return os.path.normpath(f)
    794 
    795842    def save_form_data(self, instance, data):
    796843        if data:
    797             getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
     844            getattr(instance, self.attname).save_file(data.filename, data.content, save=False)
    798845
    799846    def formfield(self, **kwargs):
    800847        defaults = {'form_class': forms.FileField}
     
    824871        defaults.update(kwargs)
    825872        return super(FloatField, self).formfield(**defaults)
    826873
     874class ImageFile(File):
     875    def get_width(self):
     876        return self._get_image_dimensions()[0]
     877
     878    def get_height(self):
     879        return self._get_image_dimensions()[1]
     880
     881    def _get_image_dimensions(self):
     882        if not hasattr(self, '_dimensions_cache'):
     883            from django.utils.images import get_image_dimensions
     884            self._dimensions_cache = get_image_dimensions(self.open())
     885        return self._dimensions_cache
     886
     887    def save_file(self, filename, raw_contents, save=True):
     888        super(ImageFile, self).save_file(filename, raw_contents, save)
     889       
     890        # Update the cache for image dimensions
     891        from django.utils.images import get_image_dimensions
     892        from cStringIO import StringIO
     893        self._dimensions_cache = get_image_dimensions(StringIO(raw_contents))
     894
    827895class ImageField(FileField):
     896    attr_class = ImageFile
     897
    828898    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
    829899        self.width_field, self.height_field = width_field, height_field
    830900        FileField.__init__(self, verbose_name, name, **kwargs)
     
    842912            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
    843913
    844914    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    845         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
    846915        # If the image has height and/or width field(s) and they haven't
    847916        # changed, set the width and/or height field(s) back to their original
    848917        # values.
    849         if change and (self.width_field or self.height_field) and save:
    850             if self.width_field:
    851                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
    852             if self.height_field:
    853                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    854             new_object.save()
     918        if self.width_field or self.height_field:
     919            if original_object and not change:
     920                if self.width_field:
     921                    setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     922                if self.height_field:
     923                    setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     924            else:
     925                from cStringIO import StringIO
     926                from django.utils.images import get_image_dimensions
    855927
     928                upload_field_name = self.get_manipulator_field_names('')[0]
     929                if rel:
     930                    field = new_data[upload_field_name][0]
     931                else:
     932                    field = new_data[upload_field_name]
     933
     934                # Get the width and height from the raw content to avoid extra
     935                # unnecessary trips to the file backend.
     936                width, height = get_image_dimensions(StringIO(field["content"]))
     937
     938                if self.width_field:
     939                    setattr(new_object, self.width_field, width)
     940                if self.height_field:
     941                    setattr(new_object, self.height_field, height)
     942        FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
     943
    856944    def formfield(self, **kwargs):
    857945        defaults = {'form_class': forms.ImageField}
    858946        defaults.update(kwargs)
  • django/utils/images.py

     
    66
    77import ImageFile
    88
    9 def get_image_dimensions(path):
    10     """Returns the (width, height) of an image at a given path."""
     9def get_image_dimensions(file_or_path):
     10    """Returns the (width, height) of an image, given an open file or a path."""
    1111    p = ImageFile.Parser()
    12     fp = open(path, 'rb')
     12    if hasattr(file_or_path, 'read'):
     13        fp = file_or_path
     14    else:
     15        fp = open(file_or_path, 'rb')
    1316    while 1:
    1417        data = fp.read(1024)
    1518        if not data:
     
    1922            return p.image.size
    2023            break
    2124    fp.close()
    22     return None
     25    return None
     26 No newline at end of file
  • docs/db-api.txt

     
    18711871get_FOO_filename()
    18721872------------------
    18731873
     1874**Deprecated in Django development version. See `managing files` for the new,
     1875preferred method for dealing with files.**
     1876
    18741877For every ``FileField``, the object will have a ``get_FOO_filename()`` method,
    18751878where ``FOO`` is the name of the field. This returns the full filesystem path
    18761879to the file, according to your ``MEDIA_ROOT`` setting.
     
    18811884get_FOO_url()
    18821885-------------
    18831886
     1887**Deprecated in Django development version. See `managing files` for the new,
     1888preferred method for dealing with files.**
     1889
    18841890For every ``FileField``, the object will have a ``get_FOO_url()`` method,
    18851891where ``FOO`` is the name of the field. This returns the full URL to the file,
    18861892according to your ``MEDIA_URL`` setting. If the value is blank, this method
     
    18891895get_FOO_size()
    18901896--------------
    18911897
     1898**Deprecated in Django development version. See `managing files` for the new,
     1899preferred method for dealing with files.**
     1900
    18921901For every ``FileField``, the object will have a ``get_FOO_size()`` method,
    18931902where ``FOO`` is the name of the field. This returns the size of the file, in
    18941903bytes. (Behind the scenes, it uses ``os.path.getsize``.)
     
    18961905save_FOO_file(filename, raw_contents)
    18971906-------------------------------------
    18981907
     1908**Deprecated in Django development version. See `managing files` for the new,
     1909preferred method for dealing with files.**
     1910
    18991911For every ``FileField``, the object will have a ``save_FOO_file()`` method,
    19001912where ``FOO`` is the name of the field. This saves the given file to the
    19011913filesystem, using the given filename. If a file with the given filename already
     
    19051917get_FOO_height() and get_FOO_width()
    19061918------------------------------------
    19071919
     1920**Deprecated in Django development version. See `managing files` for the new,
     1921preferred method for dealing with files.**
     1922
    19081923For every ``ImageField``, the object will have ``get_FOO_height()`` and
    19091924``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This
    19101925returns the height (or width) of the image, as an integer, in pixels.
  • docs/files.txt

     
     1==============
     2Managing files
     3==============
     4
     5When dealing with files, Django provides a number of features to make this task
     6easier and more portable. A backend protocol is available to allow files to be
     7stored in a variety of locations, and a special object is provided to allow
     8models to make use of this protocol, without having to worry about which storage
     9system is being used.
     10
     11Using files in models
     12=====================
     13
     14When accessing a ``FileField`` attached to a model, a special object provides
     15access to the file and information about it.
     16
     17get_absolute_path()
     18-------------------
     19
     20Returns the absolute path to the file's location on a local filesystem. For
     21backends which do not store files locally, this will return `None`.
     22
     23get_absolute_url()
     24------------------
     25
     26Provides a URL where the content of the file can be retrieved. Therefore,
     27returned from this method is suitable for use as the destination of a link to
     28the file.
     29
     30get_filesize()
     31--------------
     32
     33Returns the size of the file, as an integer.
     34
     35open(mode='rb')
     36---------------
     37
     38Returns an open file object, providing read or write access to the file's
     39contents. The ``mode`` argument allows the same values as Python's standard
     40``open()`` function.
     41
     42save_file(filename, raw_contents, save=True)
     43--------------------------------------------
     44
     45Saves a new file with the filename and contents provided. This will not replace
     46the existing file, but will create a new file and update the object to point to
     47it. The optional ``save`` argument dictates whether the model instance will be
     48saved to the database immediately.
     49
     50get_width() and get_height()
     51----------------------------
     52
     53When using an ``ImageField``, these two methods will be available, providing
     54easy access to the dimensions of the image.
     55
     56Example
     57-------
     58
     59Consider the following model, using an ``ImageField`` to store a product photo::
     60
     61    class Product(models.Model):
     62        name = models.CharField(maxlength=255)
     63        price = models.DecimalField(max_digits=5, decimal_places=2)
     64        photo = models.ImageField(upload_to='product_photos')
     65
     66Your views can then use the ``photo`` attribute with the functions described
     67above, as follows::
     68
     69    >>> car = Product.object.get(name="'57 Chevy")
     70    >>> car.photo.get_absolute_url()
     71    '/products/photo/123.jpg'
     72    >>> car.photo.get_width(), car.photo.get_height()
     73    (800, 600)
     74
     75Specifying a storage backend
     76============================
     77
     78When using a storage backend, supply whatever options are appropriate for
     79that backend when creating a new object. Details on the requirements for the
     80included backends can be found below. Then pass that object as the ``backend``
     81argument to a ``FileField``.
     82
     83If using the ``FileSystemBackend``, it is not necessary to create a backend
     84object explicitly. Simply supplying the ``upload_to`` argument will create the
     85backend object automatically.
     86
     87See the ```FileField`` documentation`_ for more information on using the field.
     88
     89.. _FileField documentation: ../model-api/#filefield
     90
     91For example, the following code will explicitly use the ``FileSystemBackend``::
     92
     93    from django.db import models
     94    from django.core.filestorage.filesystem import FileSystemBackend
     95   
     96    fs = FileSystemBackend(location='product_photos')
     97   
     98    class Product(models.Model):
     99        name = models.CharField(maxlength=255)
     100        price = models.DecimalField(max_digits=5, decimal_places=2)
     101        photo = models.ImageField(backend=fs)
     102
     103Available backends
     104==================
     105
     106Only one storage backend is supplied in the official Django distribution, but
     107more may be available elsewhere. The documentation for the ``FileSystemBackend``
     108requirements will not necessarily be the same for other backends, so see the
     109documentation included with the backend if you use a different one.
     110
     111FileSystemBackend
     112-----------------
     113
     114This backend stores files on the system's standard filesystem. It requires just
     115one argument, while two more are optional:
     116
     117    ======================  ===================================================
     118    Argument                Description
     119    ======================  ===================================================
     120    ``location``            A local filesystem path that will be appended to
     121                            your ``MEDIA_ROOT`` setting to determine the
     122                            output of the ``get_<fieldname>_url()`` helper
     123                            function.
     124    ``media_root``          Absolute path to the directory that holds the files
     125                            for this backend. If omitted, it will be set to the
     126                            value of your ``MEDIA_ROOT`` setting.
     127    ``media_url``           URL that serves the files stored in this backend.
     128                            If omitted, it will default to the value of your
     129                            ``MEDIA_URL`` setting.
     130    ======================  ===================================================
     131
     132Writing a storage backend
     133=========================
     134
     135While filesystem storage is suitable for most needs, there are many other file
     136uses that require access to different storage mechanisms. In order to access
     137alternate storage systems, it's fairly simple to write a new storage backend,
     138creating a wrapper around whatever libraries are used to access your files.
     139
     140Storage backends extend ``django.core.filestorage.Backend`` and provide a set of
     141methods to do the work of actually interfacing the the storage system.
     142
     143get_available_filename(filename)
     144--------------------------------
     145
     146Returns a filename that is available in the storage mechanism. The ``filename``
     147argument is the name originally given to the file, so this method may take that
     148name into account when generating a new filename.
     149
     150This method is provided on the base ``Backend`` class, which simply appends
     151underscores to the filename until it finds
     152
     153get_filesize(filename)
     154----------------------
     155
     156Returns the total size of the file referenced by ``filename``, as an integer.
     157
     158get_absolute_url(filename)
     159--------------------------
     160
     161Provides a URL where the contents of the file referenced by ``filename`` can be
     162accessed.
     163
     164file_exists(filename)
     165---------------------
     166
     167Returns ``True`` or ``False, indicating whether there is already a file present
     168at the location referenced by``filename``. The ``get_available_filename()`` uses
     169this method to determine whether a file is available, before trying a new name.
     170
     171open(filename, mode='rb')
     172-------------------------
     173
     174Returns an open file, or file-like, object to provide access to the contents of
     175the file referenced by ``filename``. The ``mode`` argument allows the same
     176values as Python's standard ``open()`` function.
     177
     178The object returned should function like a standard `file object`_, but there is
     179a class available, ``django.core.filestorage.RemoteFile``, which makes this task
     180easier. Creating an instance of this object requires three arguments, which are
     181desribed below.
     182
     183    ======================  ===================================================
     184    Argument                Description
     185    ======================  ===================================================
     186    ``data``                The raw content of the file.
     187    ``mode``                The access mode that was passed to the ``open()``
     188                            method.
     189    ``writer``              A function that will be used to write the contents
     190                            to the backend-specific storage mechanism. The
     191                            function provided here will need to take a single
     192                            argument, which will be the raw content to be
     193                            written to the file.
     194    ======================  ===================================================
     195
     196.. _file object: http://docs.python.org/lib/bltin-file-objects.html
     197
     198save_file(filename, raw_contents)
     199---------------------------------
     200
     201Saves a new file using the backend-specific storage mechanism. The ``filename``
     202passed to this method will be the original file's name, and might not be
     203available in the actual storage system.
     204
     205This method is therefore responsible for identifying an available filename,
     206usually using ``get_available_filename()`` method described above. This method
     207must then return the actual filename that was used to store the file.
     208
     209delete_file(filename)
     210---------------------
     211
     212Deletes the file referenced by ``filename``. If the file does not already exist,
     213this method should simply return without throwing an error.
     214 No newline at end of file
  • docs/model-api.txt

     
    230230``FileField``
    231231~~~~~~~~~~~~~
    232232
    233 A file-upload field. Has one **required** argument:
     233A file-upload field. **Requires** exactly one of the following two arguments:
    234234
    235235    ======================  ===================================================
    236236    Argument                Description
    237237    ======================  ===================================================
    238238    ``upload_to``           A local filesystem path that will be appended to
    239239                            your ``MEDIA_ROOT`` setting to determine the
    240                             output of the ``get_<fieldname>_url()`` helper
    241                             function.
     240                            final storage destination. If this argument is
     241                            supplied, the storage backend will default to
     242                            ``FileSystemBackend``.
     243    ``backend``             **New in Django development version**
     244
     245                            A storage backend object, which handles the storage
     246                            and retrieval of your files. See `managing files`_
     247                            for details on how to provide this object.
    242248    ======================  ===================================================
    243249
    244 This path may contain `strftime formatting`_, which will be replaced by the
    245 date/time of the file upload (so that uploaded files don't fill up the given
    246 directory).
     250.. _managing files: ../files/
    247251
     252The ``upload_to`` path may contain `strftime formatting`_, which will be
     253replaced by the date/time of the file upload (so that uploaded files don't fill
     254up the given directory).
     255
    248256The admin represents this field as an ``<input type="file">`` (a file-upload
    249257widget).
    250258
    251 Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few
    252 steps:
     259Using a ``FileField`` or an ``ImageField`` (see below) in a model without a
     260specified backend takes a few steps:
    253261
    254262    1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the
    255263       full path to a directory where you'd like Django to store uploaded
Back to Top