Django

Code

Ticket #5361: filestorage.2.diff

File filestorage.2.diff, 37.3 kB (added by Marty Alchin <gulopine@gamemusic.org>, 10 months ago)

Fixed a tyop and added missing documentation in the last patch

  • django/core/filestorage/__init__.py

    old new  
     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

    old new  
     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

    old new  
     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

    old new  
     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

    old new  
    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

    old new  
    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

    old new  
    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 
  • docs/db-api.txt

    old new  
    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

    old new  
     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. 
  • docs/model-api.txt

    old new  
    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