Ticket #5361: filestorage.2.diff

File filestorage.2.diff, 37.3 KB (added by Marty Alchin <gulopine@…>, 7 years ago)

Fixed a tyop and added missing documentation in the last patch

  • django/core/filestorage/__init__.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_filename(self, filename):
     17        return filename
     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 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    def _get_absolute_path(self, filename):
     35        return os.path.normpath(os.path.join(self.media_root, filename))
     36
     37    # The following methods define the Backend API
     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/core/filestorage/__init__.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_filename(self, filename):
     17        return filename
     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 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    def _get_absolute_path(self, filename):
     35        return os.path.normpath(os.path.join(self.media_root, filename))
     36
     37    # The following methods define the Backend API
     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"
     
    357358        return getattr(self, cachename)
    358359
    359360    def _get_FIELD_filename(self, field):
    360         if getattr(self, field.attname): # value is not blank
    361             return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
    362         return ''
     361        warn("Use instance.%s.open() if you need access to the file." % field.attname, DeprecationWarning)
     362        return field.backend._get_absolute_path(self.__dict__[field.attname])
    363363
    364364    def _get_FIELD_url(self, field):
    365         if getattr(self, field.attname): # value is not blank
    366             import urlparse
    367             return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
    368         return ''
     365        warn("Use instance.%s.get_absolute_url()." % field.attname, DeprecationWarning)
     366        return getattr(self, field.attname).get_absolute_url()
    369367
    370368    def _get_FIELD_size(self, field):
    371         return os.path.getsize(self._get_FIELD_filename(field))
     369        warn("Use instance.%s.get_filesize()." % field.attname, DeprecationWarning)
     370        return getattr(self, field.attname).get_filesize()
    372371
    373372    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
    374         directory = field.get_directory_name()
    375         try: # Create the date-based directory if it doesn't exist.
    376             os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
    377         except OSError: # Directory probably already exists.
    378             pass
    379         filename = field.get_filename(filename)
     373        warn("Use instance.%s.save_file()." % field.attname, DeprecationWarning)
     374        return getattr(self, field.attname).save_file(filename, raw_contents, save)
    380375
    381         # If the filename already exists, keep adding an underscore to the name of
    382         # the file until the filename doesn't exist.
    383         while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
    384             try:
    385                 dot_index = filename.rindex('.')
    386             except ValueError: # filename has no dot
    387                 filename += '_'
    388             else:
    389                 filename = filename[:dot_index] + '_' + filename[dot_index:]
    390 
    391         # Write the file to disk.
    392         setattr(self, field.attname, filename)
    393 
    394         full_filename = self._get_FIELD_filename(field)
    395         fp = open(full_filename, 'wb')
    396         fp.write(raw_contents)
    397         fp.close()
    398 
    399         # Save the width and/or height, if applicable.
    400         if isinstance(field, ImageField) and (field.width_field or field.height_field):
    401             from django.utils.images import get_image_dimensions
    402             width, height = get_image_dimensions(full_filename)
    403             if field.width_field:
    404                 setattr(self, field.width_field, width)
    405             if field.height_field:
    406                 setattr(self, field.height_field, height)
    407 
    408         # Save the object because it has changed unless save is False
    409         if save:
    410             self.save()
    411 
    412     _save_FIELD_file.alters_data = True
    413 
    414376    def _get_FIELD_width(self, field):
    415         return self._get_image_dimensions(field)[0]
     377        warn("Use instance.%s.get_width()." % field.attname, DeprecationWarning)
     378        return getattr(self, field.attname).get_width()
    416379
    417380    def _get_FIELD_height(self, field):
    418         return self._get_image_dimensions(field)[1]
     381        warn("Use instance.%s.get_height()." % field.attname, DeprecationWarning)
     382        return getattr(self, field.attname).get_height()
    419383
    420     def _get_image_dimensions(self, field):
    421         cachename = "__%s_dimensions_cache" % field.name
    422         if not hasattr(self, cachename):
    423             from django.utils.images import get_image_dimensions
    424             filename = self._get_FIELD_filename(field)
    425             setattr(self, cachename, get_image_dimensions(filename))
    426         return getattr(self, cachename)
    427 
    428384############################################
    429385# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
    430386############################################
  • django/db/models/fields/__init__.py

     
    694694        defaults.update(kwargs)
    695695        return super(EmailField, self).formfield(**defaults)
    696696
     697class File(object):
     698    def __init__(self, obj, field, filename):
     699        self.obj = obj
     700        self.field = field
     701        self.backend = field.backend
     702        self.filename = filename
     703
     704    def __str__(self):
     705        return self.backend.get_filename(self.filename)
     706
     707    def get_absolute_url(self):
     708        return self.backend.get_absolute_url(self.filename)
     709
     710    def get_filesize(self):
     711        if not hasattr(self, '_filesize'):
     712            self._filesize = self.backend.get_filesize(self.filename)
     713        return self._filesize
     714
     715    def open(self, mode='rb'):
     716        return self.backend.open(self.filename, mode)
     717
     718    def save_file(self, filename, raw_contents, save=True):
     719        self.filename = self.backend.save_file(filename, raw_contents)
     720
     721        # Update the filesize cache
     722        self._filesize = len(raw_contents)
     723
     724        # Save the object because it has changed, unless save is False
     725        if save:
     726            self.obj.save()
     727
     728class FileProxy(object):
     729    def __init__(self, field):
     730        self.field = field
     731        self.cache_name = self.field.get_cache_name()
     732
     733    def __get__(self, instance=None, owner=None):
     734        if instance is None:
     735            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.attname, self.owner.__name__)
     736        return getattr(instance, self.cache_name)
     737
     738    def __set__(self, instance, value):
     739        if hasattr(instance, self.cache_name):
     740            raise AttributeError, "%s can not be set in this manner." % self.field.attname
     741        instance.__dict__[self.field.attname] = value
     742        attr = self.field.attr_class(instance, self.field, value)
     743        setattr(instance, self.cache_name, attr)
     744
    697745class FileField(Field):
    698     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
    699         self.upload_to = upload_to
     746    attr_class = File
     747
     748    def __init__(self, verbose_name=None, name=None, upload_to='', backend=None, **kwargs):
     749        if backend is None:
     750            from django.db.models.fields.backends.filesystem import FileSystemBackend
     751            backend = FileSystemBackend(location=upload_to)
     752        self.backend = self.upload_to = backend
    700753        Field.__init__(self, verbose_name, name, **kwargs)
    701754
    702755    def get_db_prep_save(self, value):
     
    704757        # Need to convert UploadedFile objects provided via a form to unicode for database insertion
    705758        if value is None:
    706759            return None
    707         return unicode(value)
     760        return unicode(value.filename)
    708761
    709762    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    710763        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     
    744797
    745798    def contribute_to_class(self, cls, name):
    746799        super(FileField, self).contribute_to_class(cls, name)
     800        setattr(cls, self.attname, FileProxy(self))
    747801        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
    748802        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    749803        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    750804        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))
    751805        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
    752806
    753     def delete_file(self, instance):
    754         if getattr(instance, self.attname):
    755             file_name = getattr(instance, 'get_%s_filename' % self.name)()
    756             # If the file exists and no other object of this type references it,
    757             # delete it from the filesystem.
    758             if os.path.exists(file_name) and \
    759                 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
    760                 os.remove(file_name)
     807    def delete_file(self, instance, sender):
     808        filename = getattr(instance, self.attname).filename
     809        # If no other object of this type references the file,
     810        # delete it from the backend.
     811        if not sender._default_manager.filter(**{self.name: filename}):
     812            self.backend.delete_file(filename)
    761813
    762814    def get_manipulator_field_objs(self):
    763815        return [oldforms.FileUploadField, oldforms.HiddenField]
     
    768820    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    769821        upload_field_name = self.get_manipulator_field_names('')[0]
    770822        if new_data.get(upload_field_name, False):
    771             func = getattr(new_object, 'save_%s_file' % self.name)
    772823            if rel:
    773                 func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)
     824                field = new_data[upload_field_name][0]
    774825            else:
    775                 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
     826                field = new_data[upload_field_name]
     827            getattr(new_object, self.attname).save_file(field["filename"], field["content"], save)
    776828
    777     def get_directory_name(self):
    778         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    779 
    780     def get_filename(self, filename):
    781         from django.utils.text import get_valid_filename
    782         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    783         return os.path.normpath(f)
    784 
    785829    def save_form_data(self, instance, data):
    786830        if data:
    787             getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
    788        
     831            getattr(instance, self.attnamename).save_file(data.filename, data.content, save=False)
     832
    789833    def formfield(self, **kwargs):
    790834        defaults = {'form_class': forms.FileField}
    791835        # If a file has been provided previously, then the form doesn't require
     
    814858        defaults.update(kwargs)
    815859        return super(FloatField, self).formfield(**defaults)
    816860
     861class ImageFile(File):
     862    def get_width(self):
     863        return self._get_image_dimensions()[0]
     864
     865    def get_height(self):
     866        return self._get_image_dimensions()[1]
     867
     868    def _get_image_dimensions(self):
     869        if not hasattr(self, '_dimensions_cache'):
     870            from django.utils.images import get_image_dimensions
     871            self._dimensions_cache = get_image_dimensions(self.open())
     872        return self._dimensions_cache
     873
     874    def save_file(self, filename, raw_contents):
     875        super(ImageFile, self).save_file(filename, raw_contnts)
     876       
     877        # Update the cache for image dimensions
     878        from django.utils.images import get_image_dimensions
     879        from cStringIO import StringIO
     880        self._dimensions_cache = get_image_dimensions(StringIO(raw_contents))
     881
    817882class ImageField(FileField):
     883    attr_class = ImageFile
     884
    818885    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
    819886        self.width_field, self.height_field = width_field, height_field
    820887        FileField.__init__(self, verbose_name, name, **kwargs)
     
    832899            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
    833900
    834901    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    835         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
    836902        # If the image has height and/or width field(s) and they haven't
    837903        # changed, set the width and/or height field(s) back to their original
    838904        # values.
    839         if change and (self.width_field or self.height_field) and save:
    840             if self.width_field:
    841                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
    842             if self.height_field:
    843                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    844             new_object.save()
     905        if self.width_field or self.height_field:
     906            if original_object and not change:
     907                if self.width_field:
     908                    setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     909                if self.height_field:
     910                    setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     911            else:
     912                from cStringIO import StringIO
     913                from django.utils.images import get_image_dimensions
    845914
     915                upload_field_name = self.get_manipulator_field_names('')[0]
     916                if rel:
     917                    field = new_data[upload_field_name][0]
     918                else:
     919                    field = new_data[upload_field_name]
     920
     921                # Get the width and height from the raw content to avoid extra
     922                # unnecessary trips to the file backend.
     923                width, height = get_image_dimensions(StringIO(field["content"]))
     924
     925                if self.width_field:
     926                    setattr(new_object, self.width_field, width)
     927                if self.height_field:
     928                    setattr(new_object, self.height_field, height)
     929        FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
     930
    846931    def formfield(self, **kwargs):
    847932        defaults = {'form_class': forms.ImageField}
    848933        return super(ImageField, self).formfield(**defaults)
  • 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

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

     
    227227``FileField``
    228228~~~~~~~~~~~~~
    229229
    230 A file-upload field. Has one **required** argument:
     230A file-upload field. **Requires** exactly one of the following two arguments:
    231231
    232232    ======================  ===================================================
    233233    Argument                Description
    234234    ======================  ===================================================
    235235    ``upload_to``           A local filesystem path that will be appended to
    236236                            your ``MEDIA_ROOT`` setting to determine the
    237                             output of the ``get_<fieldname>_url()`` helper
    238                             function.
     237                            final storage destination. If this argument is
     238                            supplied, the storage backend will default to
     239                            ``FileSystemBackend``.
     240    ``backend``             **New in Django development version**
     241
     242                            A storage backend object, which handles the storage
     243                            and retrieval of your files. See `managing files`_
     244                            for details on how to provide this object.
    239245    ======================  ===================================================
    240246
    241 This path may contain `strftime formatting`_, which will be replaced by the
    242 date/time of the file upload (so that uploaded files don't fill up the given
    243 directory).
     247.. _managing files: ../files/
    244248
     249The ``upload_to`` path may contain `strftime formatting`_, which will be
     250replaced by the date/time of the file upload (so that uploaded files don't fill
     251up the given directory).
     252
    245253The admin represents this field as an ``<input type="file">`` (a file-upload
    246254widget).
    247255
    248 Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few
    249 steps:
     256Using a ``FileField`` or an ``ImageField`` (see below) in a model without a
     257specified backend takes a few steps:
    250258
    251259    1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the
    252260       full path to a directory where you'd like Django to store uploaded
Back to Top