Ticket #5361: 5361-r8222.diff

File 5361-r8222.diff, 100.6 KB (added by Marty Alchin, 16 years ago)

Updated to r8222, cleaned up File.open() and removed RemoteFile and StorageFile

  • django/conf/global_settings.py

     
    226226# Path to the "jing" executable -- needed to validate XMLFields
    227227JING_PATH = "/usr/bin/jing"
    228228
     229# Default file storage mechanism that holds media.
     230DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
     231
    229232# Absolute path to the directory that holds media.
    230233# Example: "/home/media/media.lawrence.com/"
    231234MEDIA_ROOT = ''
  • django/contrib/admin/widgets.py

     
    8585    def render(self, name, value, attrs=None):
    8686        output = []
    8787        if value:
    88             output.append('%s <a target="_blank" href="%s%s">%s</a> <br />%s ' % \
    89                 (_('Currently:'), settings.MEDIA_URL, value, value, _('Change:')))
     88            output.append('%s <a target="_blank" href="%s">%s</a> <br />%s ' % \
     89                (_('Currently:'), value.url, value, _('Change:')))
    9090        output.append(super(AdminFileWidget, self).render(name, value, attrs))
    9191        return mark_safe(u''.join(output))
    9292
  • django/core/files/__init__.py

     
     1from django.core.files.base import File
  • django/core/files/base.py

     
     1import os
     2
     3from django.utils.encoding import smart_str, smart_unicode
     4
     5try:
     6    from cStringIO import StringIO
     7except ImportError:
     8    from StringIO import StringIO
     9
     10class File(object):
     11    DEFAULT_CHUNK_SIZE = 64 * 2**10
     12
     13    def __init__(self, file):
     14        self.file = file
     15        self._name = file.name
     16        self._mode = file.mode
     17        self._closed = False
     18
     19    def __str__(self):
     20        return smart_str(self.name or '')
     21
     22    def __unicode__(self):
     23        return smart_unicode(self.name or u'')
     24
     25    def __repr__(self):
     26        return "<%s: %s>" % (self.__class__.__name__, self or "None")
     27
     28    def __nonzero__(self):
     29        return not not self.name
     30
     31    def __len__(self):
     32        return self.size
     33
     34    def _get_name(self):
     35        return self._name
     36    name = property(_get_name)
     37
     38    def _get_mode(self):
     39        return self._mode
     40    mode = property(_get_mode)
     41
     42    def _get_closed(self):
     43        return self._closed
     44    closed = property(_get_closed)
     45
     46    def _get_size(self):
     47        if not hasattr(self, '_size'):
     48            if hasattr(self.file, 'size'):
     49                self._size = self.file.size
     50            elif os.path.exists(self.file.name):
     51                self._size = os.path.getsize(self.file.name)
     52            else:
     53                raise AttributeError("Unable to determine the file's size.")
     54        return self._size
     55
     56    def _set_size(self, size):
     57        self._size = size
     58
     59    size = property(_get_size, _set_size)
     60
     61    def chunks(self, chunk_size=None):
     62        """
     63        Read the file and yield chucks of ``chunk_size`` bytes (defaults to
     64        ``UploadedFile.DEFAULT_CHUNK_SIZE``).
     65        """
     66        if not chunk_size:
     67            chunk_size = self.__class__.DEFAULT_CHUNK_SIZE
     68
     69        if hasattr(self, 'seek'):
     70            self.seek(0)
     71        # Assume the pointer is at zero...
     72        counter = self.size
     73
     74        while counter > 0:
     75            yield self.read(chunk_size)
     76            counter -= chunk_size
     77
     78    def multiple_chunks(self, chunk_size=None):
     79        """
     80        Returns ``True`` if you can expect multiple chunks.
     81
     82        NB: If a particular file representation is in memory, subclasses should
     83        always return ``False`` -- there's no good reason to read from memory in
     84        chunks.
     85        """
     86        if not chunk_size:
     87            chunk_size = self.DEFAULT_CHUNK_SIZE
     88        return self.size > chunk_size
     89
     90    def xreadlines(self):
     91        return iter(self)
     92
     93    def readlines(self):
     94        return list(self.xreadlines())
     95
     96    def __iter__(self):
     97        # Iterate over this file-like object by newlines
     98        buffer_ = None
     99        for chunk in self.chunks():
     100            chunk_buffer = StringIO(chunk)
     101
     102            for line in chunk_buffer:
     103                if buffer_:
     104                    line = buffer_ + line
     105                    buffer_ = None
     106
     107                # If this is the end of a line, yield
     108                # otherwise, wait for the next round
     109                if line[-1] in ('\n', '\r'):
     110                    yield line
     111                else:
     112                    buffer_ = line
     113
     114        if buffer_ is not None:
     115            yield buffer_
     116
     117    def open(self, mode=None):
     118        if not self.closed:
     119            self.seek(0)
     120        elif os.path.exists(self.file.name):
     121            self.file = open(self.file.name, mode or self.file.mode)
     122        else:
     123            raise ValueError("The file cannot be reopened.")
     124
     125    def seek(self, position):
     126        self.file.seek(position)
     127
     128    def tell(self):
     129        return self.file.tell()
     130
     131    def read(self, num_bytes=None):
     132        if num_bytes is None:
     133            return self.file.read()
     134        return self.file.read(num_bytes)
     135
     136    def write(self, content):
     137        if not self.mode.startswith('w'):
     138            raise IOError("File was not opened with write access.")
     139        self.file.write(content)
     140
     141    def flush(self):
     142        if not self.mode.startswith('w'):
     143            raise IOError("File was not opened with write access.")
     144        self.file.flush()
     145
     146    def close(self):
     147        self.file.close()
     148        self._closed = True
     149
     150class ContentFile(File):
     151    """
     152    A File-like object that takes just raw content, rather than an actual file.
     153    """
     154    def __init__(self, content):
     155        self.file = StringIO(content or '')
     156        self.size = len(content or '')
     157        self.file.seek(0)
     158        self._closed = False
     159
     160    def __str__(self):
     161        return 'Raw content'
     162
     163    def __nonzero__(self):
     164        return True
     165
     166    def open(self, mode=None):
     167        if self._closed:
     168            self._closed = False
     169        self.seek(0)
  • django/core/files/images.py

     
     1"""
     2Utility functions for handling images.
     3
     4Requires PIL, as you might imagine.
     5"""
     6
     7from PIL import ImageFile as PIL
     8from django.core.files import File
     9
     10class ImageFile(File):
     11    """
     12    A mixin for use alongside django.core.files.base.File, which provides
     13    additional features for dealing with images.
     14    """
     15    def _get_width(self):
     16        return self._get_image_dimensions()[0]
     17    width = property(_get_width)
     18
     19    def _get_height(self):
     20        return self._get_image_dimensions()[1]
     21    height = property(_get_height)
     22
     23    def _get_image_dimensions(self):
     24        if not hasattr(self, '_dimensions_cache'):
     25            self._dimensions_cache = get_image_dimensions(self)
     26        return self._dimensions_cache
     27
     28def get_image_dimensions(file_or_path):
     29    """Returns the (width, height) of an image, given an open file or a path."""
     30    p = PIL.Parser()
     31    if hasattr(file_or_path, 'read'):
     32        file = file_or_path
     33    else:
     34        file = open(file_or_path, 'rb')
     35    while 1:
     36        data = file.read(1024)
     37        if not data:
     38            break
     39        p.feed(data)
     40        if p.image:
     41            return p.image.size
     42    return None
  • django/core/files/storage.py

     
     1import os
     2import urlparse
     3
     4from django.conf import settings
     5from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
     6from django.utils.encoding import force_unicode, smart_str
     7from django.utils.text import force_unicode, get_valid_filename
     8from django.utils._os import safe_join
     9from django.core.files import locks, File
     10
     11__all__ = ('Storage', 'FileSystemStorage', 'DefaultStorage', 'default_storage')
     12
     13class Storage(object):
     14    """
     15    A base storage class, providing some default behaviors that all other
     16    storage systems can inherit or override, as necessary.
     17    """
     18   
     19    # The following methods represent a public interface to private methods.
     20    # These shouldn't be overridden by subclasses unless absolutely necessary.
     21
     22    def open(self, name, mode='rb', mixin=None):
     23        """
     24        Retrieves the specified file from storage, using the optional mixin
     25        class to customize what features are available on the File returned.
     26        """
     27        file = self._open(name, mode)
     28        if mixin:
     29            # Add the mixin as a parent class of the File returned from storage.
     30            file.__class__ = type(mixin.__name__, (mixin, file.__class__), {})
     31        return file
     32
     33    def save(self, name, content):
     34        """
     35        Saves new content to the file specified by name. The content should be a
     36        proper File object, ready to be read from the beginning.
     37        """
     38        # Check for old-style usage. Warn here first since there are multiple
     39        # locations where we need to support both new and old usage.
     40        if isinstance(content, basestring):
     41            import warnings
     42            warnings.warn(
     43                message = "Representing files as strings is deprecated." \
     44                          "Use django.core.files.base.ContentFile instead.",
     45                category = DeprecationWarning,
     46                stacklevel = 2
     47            )
     48            from django.core.files.base import ContentFile
     49            content = ContentFile(content)
     50
     51        # Get the proper name for the file, as it will actually be saved.
     52        if name is None:
     53            name = content.name
     54        name = self.get_available_name(name)
     55
     56        self._save(name, content)
     57
     58        # Store filenames with forward slashes, even on Windows
     59        return force_unicode(name.replace('\\', '/'))
     60
     61    # These methods are part of the public API, with default implementations.
     62
     63    def get_valid_name(self, name):
     64        """
     65        Returns a filename, based on the provided filename, that's suitable for
     66        use in the target storage system.
     67        """
     68        return get_valid_filename(name)
     69
     70    def get_available_name(self, name):
     71        """
     72        Returns a filename that's free on the target storage system, and
     73        available for new content to be written to.
     74        """
     75        # If the filename already exists, keep adding an underscore to the name
     76        # of the file until the filename doesn't exist.
     77        while self.exists(name):
     78            try:
     79                dot_index = name.rindex('.')
     80            except ValueError: # filename has no dot
     81                name += '_'
     82            else:
     83                name = name[:dot_index] + '_' + name[dot_index:]
     84        return name
     85
     86    def path(self, name):
     87        """
     88        Returns a local filesystem path where the file can be retrieved using
     89        Python's built-in open() function. Storage systems that can't be
     90        accessed using open() should *not* implement this method.
     91        """
     92        raise NotImplementedError("This backend doesn't support absolute paths.")
     93
     94    # The following methods form the public API for storage systems, but with
     95    # no default implementations. Subclasses must implement *all* of these.
     96
     97    def delete(self, name):
     98        """
     99        Deletes the specified file from the storage system.
     100        """
     101        raise NotImplementedError()
     102
     103    def exists(self, name):
     104        """
     105        Returns True if a file referened by the given name already exists in the
     106        storage system, or False if the name is available for a new file.
     107        """
     108        raise NotImplementedError()
     109
     110    def listdir(self, path):
     111        """
     112        Lists the contents of the specified path, returning a 2-tuple of lists;
     113        the first item being directories, the second item being files.
     114        """
     115        raise NotImplementedError()
     116
     117    def size(self, name):
     118        """
     119        Returns the total size, in bytes, of the file specified by name.
     120        """
     121        raise NotImplementedError()
     122
     123    def url(self, name):
     124        """
     125        Returns an absolute URL where the file's contents can be accessed
     126        directly by a web browser.
     127        """
     128        raise NotImplementedError()
     129
     130class FileSystemStorage(Storage):
     131    """
     132    Standard filesystem storage
     133    """
     134
     135    def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL):
     136        self.location = os.path.abspath(location)
     137        self.base_url = base_url
     138
     139    def _open(self, name, mode='rb'):
     140        return File(open(self.path(name), mode))
     141
     142    def _save(self, name, content):
     143        full_path = self.path(name)
     144
     145        directory = os.path.dirname(full_path)
     146        if not os.path.exists(directory):
     147            os.makedirs(directory)
     148        elif not os.path.isdir(directory):
     149            raise IOError("%s exists and is not a directory." % directory)
     150
     151        if hasattr(content, 'temporary_file_path'):
     152            # This file has a file path that we can move.
     153            file_move_safe(content.temporary_file_path(), full_path)
     154            content.close()
     155        else:
     156            # This is a normal uploadedfile that we can stream.
     157            fp = open(full_path, 'wb')
     158            locks.lock(fp, locks.LOCK_EX)
     159            for chunk in content.chunks():
     160                fp.write(chunk)
     161            locks.unlock(fp)
     162            fp.close()
     163
     164    def delete(self, name):
     165        name = self.path(name)
     166        # If the file exists, delete it from the filesystem.
     167        if os.path.exists(name):
     168            os.remove(name)
     169
     170    def exists(self, name):
     171        return os.path.exists(self.path(name))
     172
     173    def listdir(self, path):
     174        path = self.path(path)
     175        directories, files = [], []
     176        for entry in os.listdir(path):
     177            if os.path.isdir(os.path.join(path, entry)):
     178                directories.append(entry)
     179            else:
     180                files.append(entry)
     181        return directories, files
     182
     183    def path(self, name):
     184        try:
     185            path = safe_join(self.location, name)
     186        except ValueError:
     187            raise SuspiciousOperation("Attempted access to '%s' denied." % name)
     188        return os.path.normpath(path)
     189
     190    def size(self, name):
     191        return os.path.getsize(self.path(name))
     192
     193    def url(self, name):
     194        if self.base_url is None:
     195            raise ValueError("This file is not accessible via a URL.")
     196        return urlparse.urljoin(self.base_url, name).replace('\\', '/')
     197
     198def get_storage_class(import_path):
     199    try:
     200        dot = import_path.rindex('.')
     201    except ValueError:
     202        raise ImproperlyConfigured("%s isn't a storage module." % import_path)
     203    module, classname = import_path[:dot], import_path[dot+1:]
     204    try:
     205        mod = __import__(module, {}, {}, [''])
     206    except ImportError, e:
     207        raise ImproperlyConfigured('Error importing storage module %s: "%s"' % (module, e))
     208    try:
     209        return getattr(mod, classname)
     210    except AttributeError:
     211        raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
     212
     213DefaultStorage = get_storage_class(settings.DEFAULT_FILE_STORAGE)
     214default_storage = DefaultStorage()
  • django/core/files/uploadedfile.py

     
    1010    from StringIO import StringIO
    1111
    1212from django.conf import settings
     13from django.core.files.base import File
    1314
    1415from django.core.files import temp as tempfile
    1516
     
    3940    else:
    4041        return property(getter, setter)
    4142
    42 class UploadedFile(object):
     43class UploadedFile(File):
    4344    """
    4445    A abstract uploaded file (``TemporaryUploadedFile`` and
    4546    ``InMemoryUploadedFile`` are the built-in concrete subclasses).
     
    7677
    7778    name = property(_get_name, _set_name)
    7879
    79     def chunks(self, chunk_size=None):
    80         """
    81         Read the file and yield chucks of ``chunk_size`` bytes (defaults to
    82         ``UploadedFile.DEFAULT_CHUNK_SIZE``).
    83         """
    84         if not chunk_size:
    85             chunk_size = UploadedFile.DEFAULT_CHUNK_SIZE
    86 
    87         if hasattr(self, 'seek'):
    88             self.seek(0)
    89         # Assume the pointer is at zero...
    90         counter = self.size
    91 
    92         while counter > 0:
    93             yield self.read(chunk_size)
    94             counter -= chunk_size
    95 
    9680    # Deprecated properties
    9781    filename = deprecated_property(old="filename", new="name")
    9882    file_name = deprecated_property(old="file_name", new="name")
     
    10892        return self.read()
    10993    data = property(_get_data)
    11094
    111     def multiple_chunks(self, chunk_size=None):
    112         """
    113         Returns ``True`` if you can expect multiple chunks.
    114 
    115         NB: If a particular file representation is in memory, subclasses should
    116         always return ``False`` -- there's no good reason to read from memory in
    117         chunks.
    118         """
    119         if not chunk_size:
    120             chunk_size = UploadedFile.DEFAULT_CHUNK_SIZE
    121         return self.size > chunk_size
    122 
    12395    # Abstract methods; subclasses *must* define read() and probably should
    12496    # define open/close.
    12597    def read(self, num_bytes=None):
     
    131103    def close(self):
    132104        pass
    133105
    134     def xreadlines(self):
    135         return self
    136 
    137     def readlines(self):
    138         return list(self.xreadlines())
    139 
    140     def __iter__(self):
    141         # Iterate over this file-like object by newlines
    142         buffer_ = None
    143         for chunk in self.chunks():
    144             chunk_buffer = StringIO(chunk)
    145 
    146             for line in chunk_buffer:
    147                 if buffer_:
    148                     line = buffer_ + line
    149                     buffer_ = None
    150 
    151                 # If this is the end of a line, yield
    152                 # otherwise, wait for the next round
    153                 if line[-1] in ('\n', '\r'):
    154                     yield line
    155                 else:
    156                     buffer_ = line
    157 
    158         if buffer_ is not None:
    159             yield buffer_
    160 
    161106    # Backwards-compatible support for uploaded-files-as-dictionaries.
    162107    def __getitem__(self, key):
    163108        warnings.warn(
  • django/db/models/__init__.py

     
    88from django.db.models.base import Model
    99from django.db.models.fields import *
    1010from django.db.models.fields.subclassing import SubfieldBase
     11from django.db.models.fields.files import FileField, ImageField
    1112from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED
    1213from django.db.models import signals
    1314
  • django/db/models/base.py

     
    33import sys
    44import os
    55from itertools import izip
     6from warnings import warn
    67try:
    78    set
    89except NameError:
     
    1213import django.db.models.manager         # Ditto.
    1314from django.core import validators
    1415from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
    15 from django.db.models.fields import AutoField, ImageField
     16from django.db.models.fields import AutoField
    1617from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
    1718from django.db.models.query import delete_objects, Q, CollectedObjects
    1819from django.db.models.options import Options
     
    465466        return getattr(self, cachename)
    466467
    467468    def _get_FIELD_filename(self, field):
    468         if getattr(self, field.attname): # Value is not blank.
    469             return os.path.normpath(os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname)))
    470         return ''
     469        warn("instance.get_%s_filename() is deprecated. Use instance.%s.path instead." % \
     470            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     471        try:
     472            return getattr(self, field.attname).path
     473        except ValueError:
     474            return ''
    471475
    472476    def _get_FIELD_url(self, field):
    473         if getattr(self, field.attname): # Value is not blank.
    474             import urlparse
    475             return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
    476         return ''
     477        warn("instance.get_%s_url() is deprecated. Use instance.%s.url instead." % \
     478            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     479        try:
     480            return getattr(self, field.attname).url
     481        except ValueError:
     482            return ''
    477483
    478484    def _get_FIELD_size(self, field):
    479         return os.path.getsize(self._get_FIELD_filename(field))
     485        warn("instance.get_%s_size() is deprecated. Use instance.%s.size instead." % \
     486            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     487        return getattr(self, field.attname).size
    480488
    481     def _save_FIELD_file(self, field, filename, raw_field, save=True):
    482         # Create the upload directory if it doesn't already exist
    483         directory = os.path.join(settings.MEDIA_ROOT, field.get_directory_name())
    484         if not os.path.exists(directory):
    485             os.makedirs(directory)
    486         elif not os.path.isdir(directory):
    487             raise IOError('%s exists and is not a directory' % directory)       
     489    def _save_FIELD_file(self, field, filename, content, save=True):
     490        warn("instance.save_%s_file() is deprecated. Use instance.%s.save() instead." % \
     491            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     492        return getattr(self, field.attname).save(filename, content, save)
    488493
    489         # Check for old-style usage (files-as-dictionaries). Warn here first
    490         # since there are multiple locations where we need to support both new
    491         # and old usage.
    492         if isinstance(raw_field, dict):
    493             import warnings
    494             warnings.warn(
    495                 message = "Representing uploaded files as dictionaries is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",
    496                 category = DeprecationWarning,
    497                 stacklevel = 2
    498             )
    499             from django.core.files.uploadedfile import SimpleUploadedFile
    500             raw_field = SimpleUploadedFile.from_dict(raw_field)
    501 
    502         elif isinstance(raw_field, basestring):
    503             import warnings
    504             warnings.warn(
    505                 message = "Representing uploaded files as strings is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",
    506                 category = DeprecationWarning,
    507                 stacklevel = 2
    508             )
    509             from django.core.files.uploadedfile import SimpleUploadedFile
    510             raw_field = SimpleUploadedFile(filename, raw_field)
    511 
    512         if filename is None:
    513             filename = raw_field.file_name
    514 
    515         filename = field.get_filename(filename)
    516 
    517         # If the filename already exists, keep adding an underscore to the name
    518         # of the file until the filename doesn't exist.
    519         while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
    520             try:
    521                 dot_index = filename.rindex('.')
    522             except ValueError: # filename has no dot.
    523                 filename += '_'
    524             else:
    525                 filename = filename[:dot_index] + '_' + filename[dot_index:]
    526 
    527         # Save the file name on the object and write the file to disk.
    528         setattr(self, field.attname, filename)
    529         full_filename = self._get_FIELD_filename(field)
    530         if hasattr(raw_field, 'temporary_file_path'):
    531             # This file has a file path that we can move.
    532             file_move_safe(raw_field.temporary_file_path(), full_filename)
    533             raw_field.close()
    534         else:
    535             # This is a normal uploadedfile that we can stream.
    536             fp = open(full_filename, 'wb')
    537             locks.lock(fp, locks.LOCK_EX)
    538             for chunk in raw_field.chunks():
    539                 fp.write(chunk)
    540             locks.unlock(fp)
    541             fp.close()
    542 
    543         # Save the width and/or height, if applicable.
    544         if isinstance(field, ImageField) and \
    545                 (field.width_field or field.height_field):
    546             from django.utils.images import get_image_dimensions
    547             width, height = get_image_dimensions(full_filename)
    548             if field.width_field:
    549                 setattr(self, field.width_field, width)
    550             if field.height_field:
    551                 setattr(self, field.height_field, height)
    552 
    553         # Save the object because it has changed, unless save is False.
    554         if save:
    555             self.save()
    556 
    557494    _save_FIELD_file.alters_data = True
    558495
    559496    def _get_FIELD_width(self, field):
    560         return self._get_image_dimensions(field)[0]
     497        warn("instance.get_%s_width() is deprecated. Use instance.%s.width instead." % \
     498            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     499        return getattr(self, field.attname).width()
    561500
    562501    def _get_FIELD_height(self, field):
    563         return self._get_image_dimensions(field)[1]
     502        warn("instance.get_%s_height() is deprecated. Use instance.%s.height instead." % \
     503            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     504        return getattr(self, field.attname).height()
    564505
    565     def _get_image_dimensions(self, field):
    566         cachename = "__%s_dimensions_cache" % field.name
    567         if not hasattr(self, cachename):
    568             from django.utils.images import get_image_dimensions
    569             filename = self._get_FIELD_filename(field)
    570             setattr(self, cachename, get_image_dimensions(filename))
    571         return getattr(self, cachename)
    572506
    573 
    574507############################################
    575508# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
    576509############################################
  • django/db/models/fields/__init__.py

     
    88    from django.utils import _decimal as decimal    # for Python 2.3
    99
    1010from django.db import connection, get_creation_module
    11 from django.db.models import signals
    1211from django.db.models.query_utils import QueryWrapper
    1312from django.dispatch import dispatcher
    1413from django.conf import settings
     
    758757        defaults.update(kwargs)
    759758        return super(EmailField, self).formfield(**defaults)
    760759
    761 class FileField(Field):
    762     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
    763         self.upload_to = upload_to
    764         kwargs['max_length'] = kwargs.get('max_length', 100)
    765         Field.__init__(self, verbose_name, name, **kwargs)
    766 
    767     def get_internal_type(self):
    768         return "FileField"
    769 
    770     def get_db_prep_value(self, value):
    771         "Returns field's value prepared for saving into a database."
    772         # Need to convert UploadedFile objects provided via a form to unicode for database insertion
    773         if hasattr(value, 'name'):
    774             return value.name
    775         elif value is None:
    776             return None
    777         else:
    778             return unicode(value)
    779 
    780     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    781         field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
    782         if not self.blank:
    783             if rel:
    784                 # This validator makes sure FileFields work in a related context.
    785                 class RequiredFileField(object):
    786                     def __init__(self, other_field_names, other_file_field_name):
    787                         self.other_field_names = other_field_names
    788                         self.other_file_field_name = other_file_field_name
    789                         self.always_test = True
    790                     def __call__(self, field_data, all_data):
    791                         if not all_data.get(self.other_file_field_name, False):
    792                             c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
    793                             c(field_data, all_data)
    794                 # First, get the core fields, if any.
    795                 core_field_names = []
    796                 for f in opts.fields:
    797                     if f.core and f != self:
    798                         core_field_names.extend(f.get_manipulator_field_names(name_prefix))
    799                 # Now, if there are any, add the validator to this FormField.
    800                 if core_field_names:
    801                     field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
    802             else:
    803                 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
    804                 v.always_test = True
    805                 field_list[0].validator_list.append(v)
    806                 field_list[0].is_required = field_list[1].is_required = False
    807 
    808         # If the raw path is passed in, validate it's under the MEDIA_ROOT.
    809         def isWithinMediaRoot(field_data, all_data):
    810             f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
    811             if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
    812                 raise validators.ValidationError, _("Enter a valid filename.")
    813         field_list[1].validator_list.append(isWithinMediaRoot)
    814         return field_list
    815 
    816     def contribute_to_class(self, cls, name):
    817         super(FileField, self).contribute_to_class(cls, name)
    818         setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
    819         setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    820         setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    821         setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save))
    822         dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
    823 
    824     def delete_file(self, instance):
    825         if getattr(instance, self.attname):
    826             file_name = getattr(instance, 'get_%s_filename' % self.name)()
    827             # If the file exists and no other object of this type references it,
    828             # delete it from the filesystem.
    829             if os.path.exists(file_name) and \
    830                 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
    831                 os.remove(file_name)
    832 
    833     def get_manipulator_field_objs(self):
    834         return [oldforms.FileUploadField, oldforms.HiddenField]
    835 
    836     def get_manipulator_field_names(self, name_prefix):
    837         return [name_prefix + self.name + '_file', name_prefix + self.name]
    838 
    839     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    840         upload_field_name = self.get_manipulator_field_names('')[0]
    841         if new_data.get(upload_field_name, False):
    842             if rel:
    843                 file = new_data[upload_field_name][0]
    844             else:
    845                 file = new_data[upload_field_name]
    846 
    847             if not file:
    848                 return
    849 
    850             # Backwards-compatible support for files-as-dictionaries.
    851             # We don't need to raise a warning because Model._save_FIELD_file will
    852             # do so for us.
    853             try:
    854                 file_name = file.name
    855             except AttributeError:
    856                 file_name = file['filename']
    857 
    858             func = getattr(new_object, 'save_%s_file' % self.name)
    859             func(file_name, file, save)
    860 
    861     def get_directory_name(self):
    862         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    863 
    864     def get_filename(self, filename):
    865         from django.utils.text import get_valid_filename
    866         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    867         return os.path.normpath(f)
    868 
    869     def save_form_data(self, instance, data):
    870         from django.core.files.uploadedfile import UploadedFile
    871         if data and isinstance(data, UploadedFile):
    872             getattr(instance, "save_%s_file" % self.name)(data.name, data, save=False)
    873 
    874     def formfield(self, **kwargs):
    875         defaults = {'form_class': forms.FileField}
    876         # If a file has been provided previously, then the form doesn't require
    877         # that a new file is provided this time.
    878         # The code to mark the form field as not required is used by
    879         # form_for_instance, but can probably be removed once form_for_instance
    880         # is gone. ModelForm uses a different method to check for an existing file.
    881         if 'initial' in kwargs:
    882             defaults['required'] = False
    883         defaults.update(kwargs)
    884         return super(FileField, self).formfield(**defaults)
    885 
    886760class FilePathField(Field):
    887761    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    888762        self.path, self.match, self.recursive = path, match, recursive
     
    924798        defaults.update(kwargs)
    925799        return super(FloatField, self).formfield(**defaults)
    926800
    927 class ImageField(FileField):
    928     def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
    929         self.width_field, self.height_field = width_field, height_field
    930         FileField.__init__(self, verbose_name, name, **kwargs)
    931 
    932     def get_manipulator_field_objs(self):
    933         return [oldforms.ImageUploadField, oldforms.HiddenField]
    934 
    935     def contribute_to_class(self, cls, name):
    936         super(ImageField, self).contribute_to_class(cls, name)
    937         # Add get_BLAH_width and get_BLAH_height methods, but only if the
    938         # image field doesn't have width and height cache fields.
    939         if not self.width_field:
    940             setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
    941         if not self.height_field:
    942             setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
    943 
    944     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    945         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
    946         # If the image has height and/or width field(s) and they haven't
    947         # changed, set the width and/or height field(s) back to their original
    948         # values.
    949         if change and (self.width_field or self.height_field) and save:
    950             if self.width_field:
    951                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
    952             if self.height_field:
    953                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    954             new_object.save()
    955 
    956     def formfield(self, **kwargs):
    957         defaults = {'form_class': forms.ImageField}
    958         defaults.update(kwargs)
    959         return super(ImageField, self).formfield(**defaults)
    960 
    961801class IntegerField(Field):
    962802    empty_strings_allowed = False
    963803    def get_db_prep_value(self, value):
  • django/db/models/fields/files.py

     
     1import datetime
     2import os
     3
     4from django.conf import settings
     5from django.db.models.fields import Field
     6from django.core.files.base import File, ContentFile
     7from django.core.files.storage import default_storage
     8from django.core.files.images import ImageFile
     9from django.core.files.uploadedfile import UploadedFile
     10from django.utils.functional import curry
     11from django.dispatch import dispatcher
     12from django.db.models import signals
     13from django.utils.encoding import force_unicode, smart_str
     14from django.utils.translation import ugettext_lazy, ugettext as _
     15from django import oldforms
     16from django import forms
     17from django.core import validators
     18from django.db.models.loading import cache
     19
     20class FieldFile(File):
     21    def __init__(self, instance, field, name):
     22        self.instance = instance
     23        self.field = field
     24        self.storage = field.storage
     25        self._name = name or u''
     26        self._closed = False
     27
     28    def __eq__(self, other):
     29        # Older code may be expecting FileField values to be simple strings.
     30        # By overriding the == operator, it can remain backwards compatibility.
     31        if hasattr(other, 'name'):
     32            return self.name == other.name
     33        return self.name == other
     34
     35    # The standard File contains most of the necessary properties, but
     36    # FieldFiles can be instantiated without a name, so that needs to
     37    # be checked for here.
     38
     39    def _require_file(self):
     40        if not self:
     41            raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)
     42
     43    def _get_file(self):
     44        self._require_file()
     45        if not hasattr(self, '_file'):
     46            self._file = self.storage.open(self.name, 'rb')
     47        return self._file
     48    file = property(_get_file)
     49
     50    def _get_path(self):
     51        self._require_file()
     52        return self.storage.path(self.name)
     53    path = property(_get_path)
     54
     55    def _get_url(self):
     56        self._require_file()
     57        return self.storage.url(self.name)
     58    url = property(_get_url)
     59
     60    def open(self, mode='rb'):
     61        self._require_file()
     62        return super(FieldFile, self).open(mode)
     63    # open() doesn't alter the file's contents, but it does reset the pointer
     64    open.alters_data = True
     65
     66    # In addition to the standard File API, FieldFiles have extra methods
     67    # to further manipulate the underlying file, as well as update the
     68    # associated model instance.
     69
     70    def save(self, name, content, save=True):
     71        name = self.field.generate_filename(self.instance, name)
     72        self._name = self.storage.save(name, content)
     73        setattr(self.instance, self.field.name, self.name)
     74
     75        # Update the filesize cache
     76        self._size = len(content)
     77
     78        # Save the object because it has changed, unless save is False
     79        if save:
     80            self.instance.save()
     81    save.alters_data = True
     82
     83    def delete(self, save=True):
     84        self.close()
     85        self.storage.delete(self.name)
     86
     87        self._name = None
     88        setattr(self.instance, self.field.name, self.name)
     89
     90        # Delete the filesize cache
     91        if hasattr(self, '_size'):
     92            del self._size
     93
     94        if save:
     95            self.instance.save()
     96    delete.alters_data = True
     97
     98    def __getstate__(self):
     99        # FieldFile needs access to its associated model field and an instance
     100        # it's attached to in order to work properly, but the only necessary
     101        # data to be pickled is the file's name itself. Everything else will
     102        # be restored later, by FileDescriptor below.
     103        return {'_name': self.name, '_closed': False}
     104
     105class FileDescriptor(object):
     106    def __init__(self, field):
     107        self.field = field
     108
     109    def __get__(self, instance=None, owner=None):
     110        if instance is None:
     111            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.name(self.owner.__name__))
     112        file = instance.__dict__[self.field.name]
     113        if not isinstance(file, FieldFile):
     114            # Create a new instance of FieldFile, based on a given file name
     115            instance.__dict__[self.field.name] = self.field.attr_class(instance, self.field, file)
     116        elif not hasattr(file, 'field'):
     117            # The FieldFile was pickled, so some attributes need to be reset.
     118            file.instance = instance
     119            file.field = self.field
     120            file.storage = self.field.storage
     121        return instance.__dict__[self.field.name]
     122
     123    def __set__(self, instance, value):
     124        instance.__dict__[self.field.name] = value
     125
     126class FileField(Field):
     127    attr_class = FieldFile
     128
     129    def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
     130        for arg in ('core', 'primary_key', 'unique'):
     131            if arg in kwargs:
     132                raise TypeError("'%s' is not a valid argument for %s." % (arg, self.__class__))
     133
     134        self.storage = storage or default_storage
     135        self.upload_to = upload_to
     136        if callable(upload_to):
     137            self.generate_filename = upload_to
     138
     139        kwargs['max_length'] = kwargs.get('max_length', 100)
     140        super(FileField, self).__init__(verbose_name, name, **kwargs)
     141
     142    def get_internal_type(self):
     143        return "FileField"
     144
     145    def get_db_prep_lookup(self, lookup_type, value):
     146        if hasattr(value, 'name'):
     147            value = value.name
     148        return super(FileField, self).get_db_prep_lookup(lookup_type, value)
     149
     150    def get_db_prep_value(self, value):
     151        "Returns field's value prepared for saving into a database."
     152        # Need to convert File objects provided via a form to unicode for database insertion
     153        if value is None:
     154            return None
     155        return unicode(value)
     156
     157    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     158        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     159        if not self.blank:
     160            if rel:
     161                # This validator makes sure FileFields work in a related context.
     162                class RequiredFileField(object):
     163                    def __init__(self, other_field_names, other_file_field_name):
     164                        self.other_field_names = other_field_names
     165                        self.other_file_field_name = other_file_field_name
     166                        self.always_test = True
     167                    def __call__(self, field_data, all_data):
     168                        if not all_data.get(self.other_file_field_name, False):
     169                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
     170                            c(field_data, all_data)
     171                # First, get the core fields, if any.
     172                core_field_names = []
     173                for f in opts.fields:
     174                    if f.core and f != self:
     175                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     176                # Now, if there are any, add the validator to this FormField.
     177                if core_field_names:
     178                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     179            else:
     180                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
     181                v.always_test = True
     182                field_list[0].validator_list.append(v)
     183                field_list[0].is_required = field_list[1].is_required = False
     184
     185        # If the raw path is passed in, validate it's under the MEDIA_ROOT.
     186        def isWithinMediaRoot(field_data, all_data):
     187            f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
     188            if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
     189                raise validators.ValidationError(_("Enter a valid filename."))
     190        field_list[1].validator_list.append(isWithinMediaRoot)
     191        return field_list
     192
     193    def contribute_to_class(self, cls, name):
     194        super(FileField, self).contribute_to_class(cls, name)
     195        setattr(cls, self.name, FileDescriptor(self))
     196        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
     197        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
     198        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
     199        setattr(cls, 'save_%s_file' % self.name, lambda instance, name, content, save=True: instance._save_FIELD_file(self, name, content, save))
     200        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     201
     202    def delete_file(self, instance, sender):
     203        file = getattr(instance, self.attname)
     204        # If no other object of this type references the file,
     205        # and it's not the default value for future objects,
     206        # delete it from the backend.
     207        if file and file.name != self.default and \
     208            not sender._default_manager.filter(**{self.name: file.name}):
     209                file.delete(save=False)
     210        elif file:
     211            # Otherwise, just close the file, so it doesn't tie up resources.
     212            file.close()
     213
     214    def get_manipulator_field_objs(self):
     215        return [oldforms.FileUploadField, oldforms.HiddenField]
     216
     217    def get_manipulator_field_names(self, name_prefix):
     218        return [name_prefix + self.name + '_file', name_prefix + self.name]
     219
     220    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     221        upload_field_name = self.get_manipulator_field_names('')[0]
     222        if new_data.get(upload_field_name, False):
     223            if rel:
     224                file = new_data[upload_field_name][0]
     225            else:
     226                file = new_data[upload_field_name]
     227
     228            # Backwards-compatible support for files-as-dictionaries.
     229            # We don't need to raise a warning because the storage backend will
     230            # do so for us.
     231            try:
     232                filename = file.name
     233            except AttributeError:
     234                filename = file['filename']
     235            filename = self.get_filename(filename)
     236
     237            getattr(new_object, self.attname).save(filename, file, save)
     238
     239    def get_directory_name(self):
     240        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
     241
     242    def get_filename(self, filename):
     243        return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
     244
     245    def generate_filename(self, instance, filename):
     246        return os.path.join(self.get_directory_name(), self.get_filename(filename))
     247
     248    def save_form_data(self, instance, data):
     249        if data and isinstance(data, UploadedFile):
     250            getattr(instance, self.name).save(data.name, data, save=False)
     251
     252    def formfield(self, **kwargs):
     253        defaults = {'form_class': forms.FileField}
     254        # If a file has been provided previously, then the form doesn't require
     255        # that a new file is provided this time.
     256        # The code to mark the form field as not required is used by
     257        # form_for_instance, but can probably be removed once form_for_instance
     258        # is gone. ModelForm uses a different method to check for an existing file.
     259        if 'initial' in kwargs:
     260            defaults['required'] = False
     261        defaults.update(kwargs)
     262        return super(FileField, self).formfield(**defaults)
     263
     264class ImageFieldFile(ImageFile, FieldFile):
     265    def save(self, name, content, save=True):
     266        super(ImageFieldFile, self).save(name, content, save)
     267
     268        # Update the cache for image dimensions
     269        from django.core.files.images import get_image_dimensions
     270        if not hasattr(content, 'read'):
     271            content = ContentFile(name, content)
     272        self._dimensions_cache = get_image_dimensions(content)
     273
     274    def delete(self, save=True):
     275        # Clear the image dimensions cache
     276        if hasattr(self, '_dimensions_cache'):
     277            del self._dimensions_cache
     278
     279        super(ImageFieldFile, self).delete(save)
     280
     281class ImageField(FileField):
     282    attr_class = ImageFieldFile
     283
     284    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
     285        self.width_field, self.height_field = width_field, height_field
     286        FileField.__init__(self, verbose_name, name, **kwargs)
     287
     288    def get_manipulator_field_objs(self):
     289        return [oldforms.ImageUploadField, oldforms.HiddenField]
     290
     291    def contribute_to_class(self, cls, name):
     292        super(ImageField, self).contribute_to_class(cls, name)
     293        # Add get_BLAH_width and get_BLAH_height methods, but only if the
     294        # image field doesn't have width and height cache fields.
     295        if not self.width_field:
     296            setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
     297        if not self.height_field:
     298            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
     299
     300    def save_form_data(self, instance, data):
     301        # If the image has height and/or width field(s) and they haven't
     302        # changed, set the width and/or height field(s) back to their original
     303        # values.
     304        if self.width_field or self.height_field:
     305            if original_object and not change:
     306                if self.width_field:
     307                    setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     308                if self.height_field:
     309                    setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     310            else:
     311                from django.utils.images import get_image_dimensions
     312
     313                upload_field_name = self.get_manipulator_field_names('')[0]
     314                if rel:
     315                    file = new_data[upload_field_name][0]
     316                else:
     317                    file = new_data[upload_field_name]
     318
     319                # Get the width and height from the raw content to avoid extra
     320                # unnecessary trips to the file backend.
     321                width, height = get_image_dimensions(file)
     322
     323                if self.width_field:
     324                    setattr(new_object, self.width_field, width)
     325                if self.height_field:
     326                    setattr(new_object, self.height_field, height)
     327        super(ImageField, self).save_form_data(instance, data)
     328
     329    def formfield(self, **kwargs):
     330        defaults = {'form_class': forms.ImageField}
     331        defaults.update(kwargs)
     332        return super(ImageField, self).formfield(**defaults)
  • django/db/models/manipulators.py

     
    11from django.core.exceptions import ObjectDoesNotExist
    22from django import oldforms
    33from django.core import validators
    4 from django.db.models.fields import FileField, AutoField
     4from django.db.models.fields import AutoField
     5from django.db.models.fields.files import FileField
    56from django.dispatch import dispatcher
    67from django.db.models import signals
    78from django.utils.functional import curry
  • django/utils/images.py

     
    1 """
    2 Utility functions for handling images.
     1import warnings
    32
    4 Requires PIL, as you might imagine.
    5 """
     3from django.core.files.images import get_image_dimensions
    64
    7 import ImageFile
    8 
    9 def get_image_dimensions(path):
    10     """Returns the (width, height) of an image at a given path."""
    11     p = ImageFile.Parser()
    12     fp = open(path, 'rb')
    13     while 1:
    14         data = fp.read(1024)
    15         if not data:
    16             break
    17         p.feed(data)
    18         if p.image:
    19             return p.image.size
    20             break
    21     fp.close()
    22     return None
     5warnings.warn("django.utils.images has been moved to django.core.files.images.", DeprecationWarning)
  • docs/custom_model_fields.txt

     
    596596       instance, not a ``HandField``). So if your ``__unicode__()`` method
    597597       automatically converts to the string form of your Python object, you can
    598598       save yourself a lot of work.
     599
     600Writing a ``FileField`` subclass
     601=================================
     602
     603In addition to the above methods, fields that deal with files have a few other
     604special requirements which must be taken into account. The majority of the
     605mechanics provided by ``FileField``, such as controlling database storage and
     606retrieval, can remain unchanged, leaving subclasses to deal with the challenge
     607of supporting a particular type of file.
     608
     609Django provides a ``File`` class, which is used as a proxy to the file's
     610contents and operations. This can be subclassed to customzie hwo the file is
     611accessed, and what methods are available. It lives at
     612``django.db.models.fields.files``, and its default behavior is explained in the
     613`file documentation`_.
     614
     615Once a subclass of ``File`` is created, the new ``FileField`` subclass must be
     616told to use it. To do so, simply assign the new ``File`` subclass to the special
     617``attr_class`` attribute of the ``FileField`` subclass.
     618
     619.. _file documentation: ../files/
     620
     621A few suggestions
     622------------------
     623
     624In addition to the above details, there are a few guidelines which can greatly
     625improve the efficiency and readability of the field's code.
     626
     627    1. The source for Django's own ``ImageField`` (in
     628       ``django/db/models/fields/files.py``) is a great example of how to
     629       subclass ``FileField`` to support a particular type of file, as it
     630       incorporates all of the techniques described above.
     631
     632    2. Cache file attributes wherever possible. Since files may be stored in
     633       remote storage systems, retrieving them may cost extra time, or even
     634       money, that isn't always necessary. Once a file is retrieved to obtain
     635       some data about its content, cache as much of that data as possible to
     636       reduce the number of times the file must be retrieved on subsequent
     637       calls for that information.
  • docs/db-api.txt

     
    22982298get_FOO_filename()
    22992299------------------
    23002300
     2301**Deprecated in Django development version. See `managing files`_ for the new,
     2302preferred method for dealing with files.**
     2303
    23012304For every ``FileField``, the object will have a ``get_FOO_filename()`` method,
    23022305where ``FOO`` is the name of the field. This returns the full filesystem path
    23032306to the file, according to your ``MEDIA_ROOT`` setting.
     
    23132316get_FOO_url()
    23142317-------------
    23152318
     2319**Deprecated in Django development version. See `managing files`_ for the new,
     2320preferred method for dealing with files.**
     2321
    23162322For every ``FileField``, the object will have a ``get_FOO_url()`` method,
    23172323where ``FOO`` is the name of the field. This returns the full URL to the file,
    23182324according to your ``MEDIA_URL`` setting. If the value is blank, this method
     
    23262332get_FOO_size()
    23272333--------------
    23282334
     2335**Deprecated in Django development version. See `managing files`_ for the new,
     2336preferred method for dealing with files.**
     2337
    23292338For every ``FileField``, the object will have a ``get_FOO_size()`` method,
    23302339where ``FOO`` is the name of the field. This returns the size of the file, in
    23312340bytes. (Behind the scenes, it uses ``os.path.getsize``.)
     
    23332342save_FOO_file(filename, raw_contents)
    23342343-------------------------------------
    23352344
     2345**Deprecated in Django development version. See `managing files`_ for the new,
     2346preferred method for dealing with files.**
     2347
    23362348For every ``FileField``, the object will have a ``save_FOO_file()`` method,
    23372349where ``FOO`` is the name of the field. This saves the given file to the
    23382350filesystem, using the given filename. If a file with the given filename already
     
    23422354get_FOO_height() and get_FOO_width()
    23432355------------------------------------
    23442356
     2357**Deprecated in Django development version. See `managing files`_ for the new,
     2358preferred method for dealing with files.**
     2359
    23452360For every ``ImageField``, the object will have ``get_FOO_height()`` and
    23462361``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This
    23472362returns the height (or width) of the image, as an integer, in pixels.
    23482363
     2364.. _`managing files`: ../files/
     2365
    23492366Shortcuts
    23502367=========
    23512368
  • docs/files.txt

     
     1==============
     2Managing files
     3==============
     4
     5**New in Django development version**
     6
     7When dealing with files, Django provides a number of features to make this task
     8easier and more portable. A storage protocol is available to allow files to be
     9stored in a variety of locations, and a special object is provided to allow
     10models to make use of this protocol, without having to worry about which storage
     11system is being used.
     12
     13The ``File`` object
     14===================
     15
     16Any time Django references a file, it will be an instance of the ``File`` class,
     17living at ``django.core.files``, or one of its subclasses. This provides many of
     18the same features as Python's own `file object`_, but has a few additions and
     19is customized for working with large-scale applications.
     20
     21.. _file object: http://docs.python.org/lib/bltin-file-objects.html
     22
     23Example
     24-------
     25
     26While there are several `File` subclasses that get created automatically, for
     27things like file uploading, the simplest way to get access to a ``File`` is to
     28just instantiate one using a true ``file`` from Python's own ``open()``::
     29
     30    >>> from django.core.files import File
     31
     32    >>> writable = File(open('/tmp/hello_world', 'w'))
     33    >>> writable.name, writable.mode
     34    ('/tmp/hello_world', 'w')
     35    >>> writable.write('Hello, world!')
     36    >>> writable.close()
     37
     38    >>> readable = File(open('/tmp/hello_world'))
     39    >>> readable.size
     40    13
     41    >>> readable.close()
     42
     43``path``
     44--------
     45
     46Returns the absolute path to the file's location on a local filesystem. For
     47storage systems which do not store files locally, this will return ``None``.
     48
     49``url``
     50-------
     51
     52Provides a URL where the content of the file can be retrieved. Therefore,
     53returned from this method is suitable for use as the destination of a link to
     54the file.
     55
     56``size``
     57--------
     58
     59Returns the size of the file, as an integer.
     60
     61``open(mode=None)``
     62-------------------
     63
     64Reopens the file, resetting the internal pointer back to the beginning. The
     65``mode`` argument allows the same values as Python's standard ``open()``. If
     66provided, ``mode`` will override whatever mode the file was opened with, while
     67omitting it will reopen the file using the same mode used before it was closed.
     68
     69``read(num_bytes=None)``
     70------------------------
     71
     72Retrieves some content from the file, returning it as a string. The optional
     73``size`` is the number of bytes to read; if not specified, the file will be read
     74through to the end.
     75
     76``__iter__()``
     77--------------
     78
     79Iterates over the lines in the file, preserving newline characters on each line.
     80This allows the file to be used in simple loops, using ``for line in file``.
     81
     82``chunks(chunk_size=None)``
     83---------------------------
     84
     85Yields the contents of the file in smaller chunks, that can be looped over to
     86access the file without loading it all into memory at once. If ``chunk_size``
     87isn't provided, it defaults to 64 KB.
     88
     89``multiple_chunks(chunk_size=None)``
     90------------------------------------
     91
     92Returns ``True`` if the file is large enough to require multiple chunks to
     93access all of its content, or ``False`` if it can all be read in one pass. The
     94optional ``chunk_size`` works the same as in ``chunks()`` above.
     95
     96``write(content)``
     97------------------
     98
     99Writes the specified content string to the file. Depending on the storage system
     100behind the scenes, this content might not be fully committed until ``close()``
     101is called on the file.
     102
     103``close()``
     104-----------
     105
     106Closes the file, so it can't be read from or written to anymore. If there's
     107still any content that hasn't been written to the file itself, this will commit
     108that as well.
     109
     110``ImageFile``
     111=============
     112
     113Anywhere Django can open a new file, it also accepts a mixin class to support
     114more specific file types. For images, there's a more specific ``ImageFile``,
     115available from ``django.core.files.images``.
     116
     117``width and height``
     118--------------------
     119
     120When using an ``ImageField``, these two attributes will be available, providing
     121easy access to the dimensions of the image.
     122
     123Using files in models
     124=====================
     125
     126When accessing a ``FileField`` attached to a model, a special object provides
     127access to the file and information about it.
     128
     129Example
     130-------
     131
     132Consider the following model, using an ``ImageField`` to store a product photo::
     133
     134    class Product(models.Model):
     135        name = models.CharField(maxlength=255)
     136        price = models.DecimalField(max_digits=5, decimal_places=2)
     137        photo = models.ImageField(upload_to='product_photos')
     138
     139Your views can then use the ``photo`` attribute with the functions described
     140above, as follows::
     141
     142    >>> car = Product.object.get(name="'57 Chevy")
     143    >>> car.photo
     144    <ImageFieldFile: 123.jpg>
     145    >>> car.photo.url
     146    '/products/photo/123.jpg'
     147    >>> car.photo.width, car.photo.height
     148    (800, 600)
     149
     150``save(name, content, save=True)``
     151----------------------------------
     152
     153Saves a new file with the filename and contents provided. This will not replace
     154the existing file, but will create a new file and update the object to point to
     155it. The optional ``save`` argument dictates whether the model instance will be
     156saved to the database immediately.
     157
     158``delete(save=True)``
     159---------------------
     160
     161Removes the file from the model instance and deletes it from the underlying
     162storage system. The optional ``save`` argument indicates whether the model
     163instance will saved to the database immediately.
     164
     165Using a storage system with FileField
     166=====================================
     167
     168When using a storage system, supply whatever options are appropriate for
     169that system when creating a new object. Then pass that object as the ``storage``
     170argument to a ``FileField``. Details on the requirements for the included
     171storage system can be found below.
     172
     173If using the default storage system, it is not necessary to create a storage
     174object explicitly. In this case, the ``FileField`` will use the one referenced
     175by the `DEFAULT_FILE_STORAGE setting`_.
     176
     177See the `FileField documentation`_ for more information on using the field.
     178
     179.. _DEFAULT_FILE_STORAGE setting: ../settings/#default-file-storage
     180.. _FileField documentation: ../model-api/#filefield
     181
     182For example, the following code will explicitly use the ``FileSystemStorage``::
     183
     184    from django.db import models
     185    from django.core.files.storage import FileSystemStorage
     186   
     187    fs = FileSystemStorage(location='product_photos')
     188   
     189    class Product(models.Model):
     190        name = models.CharField(maxlength=255)
     191        price = models.DecimalField(max_digits=5, decimal_places=2)
     192        photo = models.ImageField(storage=fs)
     193
     194Using a storage system on its own
     195=================================
     196
     197Storage systems may also be used directly, without being attached to a model.
     198Simply use the following API on any instantiated storage system to access files
     199without having to worry about the underlying mechanism. In addition to explicit
     200storage mechanisms, the file storage module, ``django.core.files.storage``,
     201exports a ``default_storage`` object that's automatically created from the
     202``DEFAULT_FILE_STORAGE`` setting::
     203
     204    >>> from django.core.files.storage import default_storage
     205
     206With a functional storage system on hand, managing files is quite simple, with a
     207few basic methods to handle the most common operations::
     208
     209    >>> path = storage.save('/path/to/file', 'new content')
     210    >>> path
     211    u'/path/to/file'
     212    >>> storage.filesize(path)
     213    11
     214    >>> storage.open(path).read()
     215    'new content'
     216    >>> storage.delete(path)
     217    >>> storage.exists(path)
     218    False
     219
     220``exists(name)``
     221----------------
     222
     223Returns ``True`` or ``False, indicating whether there is already a file present
     224at the location referenced by``name``.
     225
     226``path(name)``
     227--------------
     228
     229Returns the local filesystem path where the file can be opened using Python's
     230standard ``open()``. For storage systems that aren't accessible from the local
     231filesystem, this will raise ``NotImplementedError`` instead.
     232
     233``size(name)``
     234--------------
     235
     236Returns the total size, in bytes, of the file referenced by ``name``.
     237
     238``url(name)``
     239-------------
     240
     241Returns the URL where the contents of the file referenced by ``name`` can be
     242accessed.
     243
     244``open(name, mode='rb', mixin=None)``
     245-------------------------------------
     246
     247Returns an open file, or file-like, object to provide access to the contents of
     248the file referenced by ``name``. The ``mode`` argument allows the same values as
     249Python's standard ``open()`` function. The ``mixin`` is an optional class that,
     250if provided, will be applied to the ``File`` object returned from this method.
     251
     252``save(name, content)``
     253-----------------------
     254
     255Saves a new file using the storage system, preferably with the name specified.
     256If there already exists a file at the location referenced by ``name``, this may
     257modify the filename as necessary to locate one that is available. Once the file
     258is saved, this method will return the filename where the file was actually
     259stored.
     260
     261``delete(name)``
     262----------------
     263
     264Deletes the file referenced by ``name``. If the file does not already exist,
     265this method will simply return without raising an exception.
     266
     267Available storage systems
     268=========================
     269
     270Only one storage system is supplied in the official Django distribution, but
     271more may be available elsewhere. If you'd like to use a different storage system
     272than the one listed below, see the documentation included with it.
     273
     274``django.core.files.storage.FileSystemStorage``
     275-----------------------------------------------
     276
     277This simply stores files on the system's standard filesystem.
     278
     279    ======================  ===================================================
     280    Argument                Description
     281    ======================  ===================================================
     282    ``location``            Optional. Absolute path to the directory that will
     283                            hold the files. If omitted, it will be set to the
     284                            value of your ``MEDIA_ROOT`` setting.
     285    ``base_url``            Optional. URL that serves the files stored at this
     286                            location. If omitted, it will default to the value
     287                            of your ``MEDIA_URL`` setting.
     288    ======================  ===================================================
     289
     290Writing a storage system
     291========================
     292
     293While the default filesystem storage is suitable for most needs, there are many
     294other storage mechanisms that may be used, and situations that will require
     295special processing. In order to use Django in these environments, it's fairly
     296simple to write a new storage system, creating a wrapper around whatever
     297libraries are used to access your files, or simply customizing method calls on
     298an existing storage class.
     299
     300If a storage system requires any configuration options to determine how it
     301should access the underlying storage mechanism or cusotmize its behavior in
     302other ways, those options should be specified in a particular way. Because the
     303default storage system is specified as a string, Django must be able to
     304instantiate it without any arguments, and any required arguments should be
     305specified as global settings, which can be referenced from the storage system.
     306For example::
     307
     308    from django.conf import settings
     309    from django.core.files.storage import Storage
     310
     311    class CustomStorage(Storage):
     312        def __init__(self, option=settings.CUSTOM_STORAGE_OPTION):
     313            ...
     314
     315Every storage system will have all the methods described above, but there are a
     316few with have default behaviors that shouldn't be overridden by these subclasses
     317in most situations. Each of these has a different set of responsibilities that
     318the storage system is expected to fulfill:
     319
     320 * ``path()`` -- unless the class provides access to files that are also
     321   accessible via the local filesystem, this should inherit the default behavior
     322   of raising a ``NotImplementedError``. For those that do represent portions of
     323   the filesystem, subclassing ``FileSystemStorage`` will typically be more
     324   appropriate anyway.
     325   
     326 * ``open()`` -- This provides some additional logic    that isn't specific to
     327   file retrieval, by supporting the ``mixin`` argument. Instead of overriding
     328   this directly, storage systems should provide an ``_open()`` method as
     329   described below.
     330   
     331 * ``save()`` -- The ``name`` provided to this is actually more a preference,
     332   because it will actually go through both ``get_valid_name()`` and
     333   ``get_available_name()`` to determine what name the will actually be given.
     334   It also returns the final name, taking care to adjust it to Unix-style paths.
     335   Since these features aren't related to actually storing the file, subclasses
     336   should instead provide a ``_save()`` method as described below.
     337
     338The default beaviors for these methods are provided by the provided ``Storage``
     339class, living at ``django.files.storage``. In addition, the two other methods
     340used by ``save()`` internally to determine the final filename, which have
     341default implementations, but can be overridden, and there are two other methods
     342that must be provided for all storage systems.
     343
     344``get_valid_name(name)``
     345------------------------
     346
     347Returns a filename suitable for use with the underlying storage system. The
     348``name`` argument passed to this method is the original filename sent to the
     349server, after having any path information removed. Override this to customize
     350how non-standard characters are converted to safe filenames.
     351
     352The code provided on ``Storage`` retains only alpha-numeric characters, periods
     353and underscores from the original filename, removing everything else.
     354
     355``get_available_name(name)``
     356----------------------------
     357
     358Returns a filename that is available in the storage mechanism, possibly taking
     359the provided filename into account. The ``name`` argument passed to this method
     360will have already cleaned to a filename valid for the storage system, according
     361to the ``get_valid_name()`` method described above.
     362
     363The code provided on ``Storage`` simply appends underscores to the filename
     364until it finds one that's available in the destination directory.
     365
     366``_open(name, mode='rb')``
     367--------------------------
     368
     369Returns an open ``File`` object that can be used to access the file's contents.
     370The ``mode`` represents all the same values as Python's own ``open()``, and
     371should be used to determine how the file can be accessed. See below for details
     372regarding how the returned ``File`` object should be behave for reading and
     373writing content.
     374
     375``_save(name, content)``
     376------------------------
     377
     378Stores the given content to the persistent storage backed by the class. The
     379``name`` will already have gone through ``get_valid_name()`` and
     380``get_available_name()``, and the ``content`` will be a ``File`` object itself.
     381This method has no return value.
     382
     383Providing a ``File``
     384--------------------
     385
     386Since the ``open()`` method returns a ``File`` object, it's expected that a
     387``Storage`` subclass will provide a customized version that's designed to
     388interact with the underlying storage system. Many methods, such as ``read()``,
     389``write()`` and ``close()``, should be overridden on this new ``File`` subclass,
     390so that it can transparently access the file's contents.
  • docs/model-api.txt

     
    224224``FileField``
    225225~~~~~~~~~~~~~
    226226
    227 A file-upload field. Has one **required** argument:
     227A file-upload field. Has two special arguments, of which the first is
     228**required**:
    228229
    229230    ======================  ===================================================
    230231    Argument                Description
    231232    ======================  ===================================================
    232     ``upload_to``           A local filesystem path that will be appended to
    233                             your ``MEDIA_ROOT`` setting to determine the
    234                             output of the ``get_<fieldname>_url()`` helper
    235                             function.
     233    ``upload_to``           Required. A filesystem-style path that will be
     234                            prepended to the filename before being committed to
     235                            the final storage destination.
     236
     237                            **New in Django development version**
     238
     239                            This may also be a callable, such as a function,
     240                            which will be called to obtain the upload path,
     241                            including the filename. See below for details.
     242
     243    ``storage``             **New in Django development version**
     244
     245                            Optional. A storage object, which handles the
     246                            storage and retrieval of your files. See `managing
     247                            files`_ for details on how to provide this object.
    236248    ======================  ===================================================
    237249
    238 This path may contain `strftime formatting`_, which will be replaced by the
    239 date/time of the file upload (so that uploaded files don't fill up the given
    240 directory).
     250.. _managing files: ../files/
    241251
     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
     256**New in Django development version**
     257
     258If a callable is provided for the ``upload_to`` argument, that callable must be
     259able to accept two arguments, and return a Unix-style path (with forward
     260slashes) to be passed along to the storage system. The two arguments that will
     261be passed are:
     262
     263    ======================  ===================================================
     264    Argument                Description
     265    ======================  ===================================================
     266    ``instance``            An instance of the model where the ``FileField`` is
     267                            defined. More specifically, this is the particular
     268                            instance where the current file is being attached.
     269                           
     270                            **Note**: In most cases, this object will not have
     271                            been saved to the database yet, so if it uses the
     272                            default ``AutoField``, *it might not yet have a
     273                            value for its primary key field*.
     274
     275    ``filename``            The filename that was originally given to the file.
     276                            This may or may not be taken into account when
     277                            determining the final destination path.
     278    ======================  ===================================================
     279
    242280The admin represents this field as an ``<input type="file">`` (a file-upload
    243281widget).
    244282
    245 Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few
    246 steps:
     283Using a ``FileField`` or an ``ImageField`` (see below) in a model without a
     284specified storage system takes a few steps:
    247285
    248286    1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the
    249287       full path to a directory where you'd like Django to store uploaded
  • docs/settings.txt

     
    426426isn't manually specified. Used with ``DEFAULT_CHARSET`` to construct the
    427427``Content-Type`` header.
    428428
     429DEFAULT_FILE_STORAGE
     430--------------------
     431
     432Default: ``'django.core.filestorage.filesystem.FileSystemStorage'``
     433
     434Default file storage class to be used for any file-related operations that don't
     435specify a particular storage system. See the `file documentation`_ for details.
     436
     437.. _file documentation: ../files/
     438
    429439DEFAULT_FROM_EMAIL
    430440------------------
    431441
  • docs/upload_handling.txt

     
    155155``UploadedFile`` objects
    156156========================
    157157
    158 All ``UploadedFile`` objects define the following methods/attributes:
     158In addition to those inherited from `File`_, all ``UploadedFile`` objects define
     159the following methods/attributes:
    159160
    160     ``UploadedFile.read(self, num_bytes=None)``
    161         Returns a byte string of length ``num_bytes``, or the complete file if
    162         ``num_bytes`` is ``None``.
    163 
    164     ``UploadedFile.chunks(self, chunk_size=None)``
    165         A generator yielding small chunks from the file. If ``chunk_size`` isn't
    166         given, chunks will be 64 KB.
    167 
    168     ``UploadedFile.multiple_chunks(self, chunk_size=None)``
    169         Returns ``True`` if you can expect more than one chunk when calling
    170         ``UploadedFile.chunks(self, chunk_size)``.
    171 
    172     ``UploadedFile.size``
    173         The size, in bytes, of the uploaded file.
    174 
    175     ``UploadedFile.name``
    176         The name of the uploaded file as provided by the user.
    177 
    178161    ``UploadedFile.content_type``
    179162        The content-type header uploaded with the file (e.g. ``text/plain`` or
    180163        ``application/pdf``). Like any data supplied by the user, you shouldn't
     
    186169        For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied
    187170        by the browser. Again, "trust but verify" is the best policy here.
    188171
    189     ``UploadedFile.__iter__()``
    190         Iterates over the lines in the file.
    191 
    192172    ``UploadedFile.temporary_file_path()``
    193173        Only files uploaded onto disk will have this method; it returns the full
    194174        path to the temporary uploaded file.
    195175
     176.. _File: ../files/
    196177
    197178Upload Handlers
    198179===============
  • tests/modeltests/files/__init__.py

    Property changes on: tests\modeltests\files
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1
  • tests/modeltests/files/models.py

     
     1"""
     242. Storing files according to a custom storage system
     3
     4FileField and its variations can take a "storage" argument to specify how and
     5where files should be stored.
     6"""
     7
     8import tempfile
     9
     10from django.db import models
     11from django.core.files.base import ContentFile
     12from django.core.files.storage import FileSystemStorage
     13from django.core.cache import cache
     14
     15temp_storage = FileSystemStorage(location=tempfile.gettempdir())
     16
     17# Write out a file to be used as default content
     18temp_storage.save('tests/default.txt', ContentFile('default content'))
     19
     20class Storage(models.Model):
     21    def custom_upload_to(self, filename):
     22        return 'foo'
     23
     24    def random_upload_to(self, filename):
     25        # This returns a different result each time,
     26        # to make sure it only gets called once.
     27        import random
     28        return '%s/%s' % (random.randint(100, 999), filename)
     29
     30    normal = models.FileField(storage=temp_storage, upload_to='tests')
     31    custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
     32    random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
     33    default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
     34
     35__test__ = {'API_TESTS':"""
     36# An object without a file has limited functionality.
     37
     38>>> obj1 = Storage()
     39>>> obj1.normal
     40<FieldFile: None>
     41>>> obj1.normal.size
     42Traceback (most recent call last):
     43...
     44ValueError: The 'normal' attribute has no file associated with it.
     45
     46# Saving a file enables full functionality.
     47
     48>>> obj1.normal.save('django_test.txt', ContentFile('content'))
     49>>> obj1.normal
     50<FieldFile: tests/django_test.txt>
     51>>> obj1.normal.size
     527
     53>>> obj1.normal.read()
     54'content'
     55
     56# Files can be read in a little at a time, if necessary.
     57
     58>>> obj1.normal.open()
     59>>> obj1.normal.read(3)
     60'con'
     61>>> obj1.normal.read()
     62'tent'
     63>>> '-'.join(obj1.normal.chunks(chunk_size=2))
     64'co-nt-en-t'
     65
     66# Save another file with the same name.
     67
     68>>> obj2 = Storage()
     69>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
     70>>> obj2.normal
     71<FieldFile: tests/django_test_.txt>
     72>>> obj2.normal.size
     7312
     74
     75# Push the objects into the cache to make sure they pickle properly
     76
     77>>> cache.set('obj1', obj1)
     78>>> cache.set('obj2', obj2)
     79>>> cache.get('obj2').normal
     80<FieldFile: tests/django_test_.txt>
     81
     82# Deleting an object deletes the file it uses, if there are no other objects
     83# still using that file.
     84
     85>>> obj2.delete()
     86>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
     87>>> obj2.normal
     88<FieldFile: tests/django_test_.txt>
     89
     90# Default values allow an object to access a single file.
     91
     92>>> obj3 = Storage.objects.create()
     93>>> obj3.default
     94<FieldFile: tests/default.txt>
     95>>> obj3.default.read()
     96'default content'
     97
     98# But it shouldn't be deleted, even if there are no more objects using it.
     99
     100>>> obj3.delete()
     101>>> obj3 = Storage()
     102>>> obj3.default.read()
     103'default content'
     104
     105# Verify the fix for #5655, making sure the directory is only determined once.
     106
     107>>> obj4 = Storage()
     108>>> obj4.random.save('random_file', ContentFile('random content'))
     109>>> obj4.random
     110<FieldFile: .../random_file>
     111
     112# Clean up the temporary files.
     113
     114>>> obj1.normal.delete()
     115>>> obj2.normal.delete()
     116>>> obj3.default.delete()
     117>>> obj4.random.delete()
     118"""}
  • tests/modeltests/model_forms/models.py

     
    1111import tempfile
    1212
    1313from django.db import models
     14from django.core.files.storage import FileSystemStorage
    1415
     16temp_storage = FileSystemStorage(tempfile.gettempdir())
     17
    1518ARTICLE_STATUS = (
    1619    (1, 'Draft'),
    1720    (2, 'Pending'),
     
    6063
    6164class TextFile(models.Model):
    6265    description = models.CharField(max_length=20)
    63     file = models.FileField(upload_to=tempfile.gettempdir())
     66    file = models.FileField(storage=temp_storage, upload_to='tests')
    6467
    6568    def __unicode__(self):
    6669        return self.description
     
    7376        # for PyPy, you need to check for the underlying modules
    7477        # If PIL is not available, this test is equivalent to TextFile above.
    7578        import Image, _imaging
    76         image = models.ImageField(upload_to=tempfile.gettempdir())
     79        image = models.ImageField(storage=temp_storage, upload_to='tests')
    7780    except ImportError:
    78         image = models.FileField(upload_to=tempfile.gettempdir())
     81        image = models.FileField(storage=temp_storage, upload_to='tests')
    7982
    8083    def __unicode__(self):
    8184        return self.description
     
    786789
    787790# FileField ###################################################################
    788791
     792# File forms.
     793
    789794>>> class TextFileForm(ModelForm):
    790795...     class Meta:
    791796...         model = TextFile
     
    808813<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    809814>>> instance = f.save()
    810815>>> instance.file
    811 u'...test1.txt'
     816<FieldFile: tests/test1.txt>
    812817
    813 >>> os.unlink(instance.get_file_filename())
     818>>> instance.file.delete()
    814819
    815820>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')})
    816821>>> f.is_valid()
     
    819824<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    820825>>> instance = f.save()
    821826>>> instance.file
    822 u'...test1.txt'
     827<FieldFile: tests/test1.txt>
    823828
    824829# Edit an instance that already has the file defined in the model. This will not
    825830# save the file again, but leave it exactly as it is.
     
    828833>>> f.is_valid()
    829834True
    830835>>> f.cleaned_data['file']
    831 u'...test1.txt'
     836<FieldFile: tests/test1.txt>
    832837>>> instance = f.save()
    833838>>> instance.file
    834 u'...test1.txt'
     839<FieldFile: tests/test1.txt>
    835840
    836841# Delete the current file since this is not done by Django.
    837 >>> os.unlink(instance.get_file_filename())
     842>>> instance.file.delete()
    838843
    839844# Override the file by uploading a new one.
    840845
     
    843848True
    844849>>> instance = f.save()
    845850>>> instance.file
    846 u'...test2.txt'
     851<FieldFile: tests/test2.txt>
    847852
    848853# Delete the current file since this is not done by Django.
    849 >>> os.unlink(instance.get_file_filename())
     854>>> instance.file.delete()
    850855
    851856>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')})
    852857>>> f.is_valid()
    853858True
    854859>>> instance = f.save()
    855860>>> instance.file
    856 u'...test2.txt'
     861<FieldFile: tests/test2.txt>
    857862
    858863# Delete the current file since this is not done by Django.
    859 >>> os.unlink(instance.get_file_filename())
     864>>> instance.file.delete()
    860865
    861866>>> instance.delete()
    862867
     
    868873True
    869874>>> instance = f.save()
    870875>>> instance.file
    871 ''
     876<FieldFile: None>
    872877
    873878>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance)
    874879>>> f.is_valid()
    875880True
    876881>>> instance = f.save()
    877882>>> instance.file
    878 u'...test3.txt'
     883<FieldFile: tests/test3.txt>
    879884
    880885# Delete the current file since this is not done by Django.
    881 >>> os.unlink(instance.get_file_filename())
     886>>> instance.file.delete()
    882887>>> instance.delete()
    883888
    884889>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')})
     
    886891True
    887892>>> instance = f.save()
    888893>>> instance.file
    889 u'...test3.txt'
     894<FieldFile: tests/test3.txt>
    890895
    891896# Delete the current file since this is not done by Django.
    892 >>> os.unlink(instance.get_file_filename())
     897>>> instance.file.delete()
    893898>>> instance.delete()
    894899
    895900# ImageField ###################################################################
     
    911916<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    912917>>> instance = f.save()
    913918>>> instance.image
    914 u'...test.png'
     919<ImageFieldFile: tests/test.png>
    915920
    916921# Delete the current file since this is not done by Django.
    917 >>> os.unlink(instance.get_image_filename())
     922>>> instance.image.delete()
    918923
    919924>>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
    920925>>> f.is_valid()
     
    923928<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    924929>>> instance = f.save()
    925930>>> instance.image
    926 u'...test.png'
     931<ImageFieldFile: tests/test.png>
    927932
    928933# Edit an instance that already has the image defined in the model. This will not
    929934# save the image again, but leave it exactly as it is.
     
    932937>>> f.is_valid()
    933938True
    934939>>> f.cleaned_data['image']
    935 u'...test.png'
     940<ImageFieldFile: tests/test.png>
    936941>>> instance = f.save()
    937942>>> instance.image
    938 u'...test.png'
     943<ImageFieldFile: tests/test.png>
    939944
    940945# Delete the current image since this is not done by Django.
    941946
    942 >>> os.unlink(instance.get_image_filename())
     947>>> instance.image.delete()
    943948
    944949# Override the file by uploading a new one.
    945950
     
    948953True
    949954>>> instance = f.save()
    950955>>> instance.image
    951 u'...test2.png'
     956<ImageFieldFile: tests/test2.png>
    952957
    953958# Delete the current file since this is not done by Django.
    954 >>> os.unlink(instance.get_image_filename())
     959>>> instance.image.delete()
    955960>>> instance.delete()
    956961
    957962>>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)})
     
    959964True
    960965>>> instance = f.save()
    961966>>> instance.image
    962 u'...test2.png'
     967<ImageFieldFile: tests/test2.png>
    963968
    964969# Delete the current file since this is not done by Django.
    965 >>> os.unlink(instance.get_image_filename())
     970>>> instance.image.delete()
    966971>>> instance.delete()
    967972
    968973# Test the non-required ImageField
     
    973978True
    974979>>> instance = f.save()
    975980>>> instance.image
    976 ''
     981<ImageFieldFile: None>
    977982
    978983>>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance)
    979984>>> f.is_valid()
    980985True
    981986>>> instance = f.save()
    982987>>> instance.image
    983 u'...test3.png'
     988<ImageFieldFile: tests/test3.png>
    984989
    985990# Delete the current file since this is not done by Django.
    986 >>> os.unlink(instance.get_image_filename())
     991>>> instance.image.delete()
    987992>>> instance.delete()
    988993
    989994>>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)})
     
    991996True
    992997>>> instance = f.save()
    993998>>> instance.image
    994 u'...test3.png'
     999<ImageFieldFile: tests/test3.png>
    9951000>>> instance.delete()
    9961001
    9971002# Media on a ModelForm ########################################################
  • tests/regressiontests/admin_widgets/models.py

     
    11
    22from django.conf import settings
    33from django.db import models
     4from django.core.files.storage import default_storage
    45
    56class Member(models.Model):
    67    name = models.CharField(max_length=100)
     
    1819class Album(models.Model):
    1920    band = models.ForeignKey(Band)
    2021    name = models.CharField(max_length=100)
     22    cover_art = models.ImageField(upload_to='albums')
    2123   
    2224    def __unicode__(self):
    2325        return self.name
     
    4648>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
    4749<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
    4850
     51>>> band = Band.objects.create(pk=1, name='Linkin Park')
     52>>> album = band.album_set.create(name='Hybrid Theory', cover_art=r'albums\hybrid_theory.jpg')
     53
    4954>>> w = AdminFileWidget()
    50 >>> print conditional_escape(w.render('test', 'test'))
    51 Currently: <a target="_blank" href="%(MEDIA_URL)stest">test</a> <br />Change: <input type="file" name="test" />
     55>>> print conditional_escape(w.render('test', album.cover_art))
     56Currently: <a target="_blank" href="%(STORAGE_URL)salbums/hybrid_theory.jpg">albums\hybrid_theory.jpg</a> <br />Change: <input type="file" name="test" />
    5257
    53 >>> band = Band.objects.create(pk=1, name='Linkin Park')
    54 >>> album = band.album_set.create(name='Hybrid Theory')
    55 
    5658>>> rel = Album._meta.get_field('band').rel
    5759>>> w = ForeignKeyRawIdWidget(rel)
    5860>>> print conditional_escape(w.render('test', band.pk, attrs={}))
     
    8183
    8284""" % {
    8385    'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX,
    84     'MEDIA_URL': settings.MEDIA_URL,
     86    'STORAGE_URL': default_storage.url(''),
    8587}}
  • tests/regressiontests/bug639/models.py

     
    11import tempfile
     2
    23from django.db import models
     4from django.core.files.storage import FileSystemStorage
    35
     6temp_storage = FileSystemStorage(tempfile.gettempdir())
     7
    48class Photo(models.Model):
    59    title = models.CharField(max_length=30)
    6     image = models.FileField(upload_to=tempfile.gettempdir())
     10    image = models.FileField(storage=temp_storage, upload_to='tests')
    711   
    812    # Support code for the tests; this keeps track of how many times save() gets
    913    # called on each instance.
    1014    def __init__(self, *args, **kwargs):
    11        super(Photo, self).__init__(*args, **kwargs)
    12        self._savecount = 0
     15        super(Photo, self).__init__(*args, **kwargs)
     16        self._savecount = 0
    1317   
    1418    def save(self):
    1519        super(Photo, self).save()
    16         self._savecount +=1
    17  No newline at end of file
     20        self._savecount += 1
  • tests/regressiontests/bug639/tests.py

     
    3636        Make sure to delete the "uploaded" file to avoid clogging /tmp.
    3737        """
    3838        p = Photo.objects.get()
    39         os.unlink(p.get_image_filename())
     39        p.image.delete(save=False)
  • tests/regressiontests/file_uploads/models.py

     
    11import tempfile
    22import os
    33from django.db import models
     4from django.core.files.storage import FileSystemStorage
    45
    5 UPLOAD_ROOT = tempfile.mkdtemp()
    6 UPLOAD_TO = os.path.join(UPLOAD_ROOT, 'test_upload')
     6temp_storage = FileSystemStorage(tempfile.mkdtemp())
     7UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
    78
    89class FileModel(models.Model):
    9     testfile = models.FileField(upload_to=UPLOAD_TO)
     10    testfile = models.FileField(storage=temp_storage, upload_to='test_upload')
  • tests/regressiontests/file_uploads/tests.py

     
    99from django.utils import simplejson
    1010from django.utils.hashcompat import sha_constructor
    1111
    12 from models import FileModel, UPLOAD_ROOT, UPLOAD_TO
     12from models import FileModel, temp_storage, UPLOAD_TO
    1313
    1414class FileUploadTests(TestCase):
    1515    def test_simple_upload(self):
     
    194194    """
    195195    def setUp(self):
    196196        self.obj = FileModel()
    197         if not os.path.isdir(UPLOAD_ROOT):
    198             os.makedirs(UPLOAD_ROOT)
     197        if not os.path.isdir(temp_storage.location):
     198            os.makedirs(temp_storage.location)
    199199
    200200    def tearDown(self):
    201         os.chmod(UPLOAD_ROOT, 0700)
    202         shutil.rmtree(UPLOAD_ROOT)
     201        os.chmod(temp_storage.location, 0700)
     202        shutil.rmtree(temp_storage.location)
    203203
    204204    def test_readonly_root(self):
    205205        """Permission errors are not swallowed"""
    206         os.chmod(UPLOAD_ROOT, 0500)
     206        os.chmod(temp_storage.location, 0500)
    207207        try:
    208             self.obj.save_testfile_file('foo.txt', SimpleUploadedFile('foo.txt', 'x'))
     208            self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', 'x'))
    209209        except OSError, err:
    210210            self.assertEquals(err.errno, errno.EACCES)
    211         except:
    212             self.fail("OSError [Errno %s] not raised" % errno.EACCES)
     211        except Exception, err:
     212            self.fail("OSError [Errno %s] not raised." % errno.EACCES)
    213213
    214214    def test_not_a_directory(self):
    215215        """The correct IOError is raised when the upload directory name exists but isn't a directory"""
     
    217217        fd = open(UPLOAD_TO, 'w')
    218218        fd.close()
    219219        try:
    220             self.obj.save_testfile_file('foo.txt', SimpleUploadedFile('foo.txt', 'x'))
     220            self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', 'x'))
    221221        except IOError, err:
    222222            # The test needs to be done on a specific string as IOError
    223223            # is raised even without the patch (just not early enough)
    224224            self.assertEquals(err.args[0],
    225                               "%s exists and is not a directory" % UPLOAD_TO)
     225                              "%s exists and is not a directory." % UPLOAD_TO)
    226226        except:
    227227            self.fail("IOError not raised")
  • tests/regressiontests/serializers_regress/models.py

     
    157157class EmailPKData(models.Model):
    158158    data = models.EmailField(primary_key=True)
    159159
    160 class FilePKData(models.Model):
    161     data = models.FileField(primary_key=True, upload_to='/foo/bar')
     160# class FilePKData(models.Model):
     161#    data = models.FileField(primary_key=True, upload_to='/foo/bar')
    162162
    163163class FilePathPKData(models.Model):
    164164    data = models.FilePathField(primary_key=True)
  • tests/regressiontests/serializers_regress/tests.py

     
    144144    (data_obj, 41, EmailData, None),
    145145    (data_obj, 42, EmailData, ""),
    146146    (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
    147     (data_obj, 51, FileData, None),
     147#     (data_obj, 51, FileData, None),
    148148    (data_obj, 52, FileData, ""),
    149149    (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
    150150    (data_obj, 61, FilePathData, None),
     
    242242#     (pk_obj, 620, DatePKData, datetime.date(2006,6,16)),
    243243#     (pk_obj, 630, DateTimePKData, datetime.datetime(2006,6,16,10,42,37)),
    244244    (pk_obj, 640, EmailPKData, "hovercraft@example.com"),
    245     (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
     245#     (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
    246246    (pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
    247247    (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
    248248    (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
  • tests/regressiontests/storage/__init__.py

    Property changes on: tests\regressiontests\storage
    ___________________________________________________________________
    Name: svn:ignore
       + *.pyc
    
    
     
     1
  • tests/regressiontests/storage/models.py

     
     1# Empty file to force tests to run
  • tests/regressiontests/storage/tests.py

     
     1"""
     2Tests for the file storage mechanism
     3
     4>>> import tempfile
     5>>> from django.core.files.storage import FileSystemStorage
     6>>> from django.core.files.base import ContentFile
     7
     8>>> temp_storage = FileSystemStorage(location=tempfile.gettempdir())
     9
     10# Standard file access options are available, and work as expected.
     11
     12>>> temp_storage.exists('storage_test')
     13False
     14>>> file = temp_storage.open('storage_test', 'w')
     15>>> file.write('storage contents')
     16>>> file.close()
     17
     18>>> temp_storage.exists('storage_test')
     19True
     20>>> file = temp_storage.open('storage_test', 'r')
     21>>> file.read()
     22'storage contents'
     23>>> file.close()
     24
     25>>> temp_storage.delete('storage_test')
     26>>> temp_storage.exists('storage_test')
     27False
     28
     29# Files can only be accessed if they're below the specified location.
     30
     31>>> temp_storage.exists('..')
     32Traceback (most recent call last):
     33...
     34SuspiciousOperation: Attempted access to '..' denied.
     35>>> temp_storage.open('/etc/passwd')
     36Traceback (most recent call last):
     37  ...
     38SuspiciousOperation: Attempted access to '/etc/passwd' denied.
     39
     40# RemoteFile allows files to be committed by way of a user-defined function.
     41
     42>>> from django.core.files.remote import RemoteFile
     43>>> def write_file(contents):
     44...     print 'Writing %s' % contents
     45
     46# Opening for read access doesn't commit back to the server
     47
     48>>> file = RemoteFile('', 'r', write_file)
     49>>> file.close()
     50
     51# The same goes for opening for write access, but not actually writing
     52
     53>>> file = RemoteFile('', 'w', write_file)
     54>>> file.close()
     55
     56# But once it's written to, it gets committed on close
     57
     58>>> file = RemoteFile('', 'w', write_file)
     59>>> file.write('remote contents') # Content isn't committed yet
     60>>> file.close() # Content gets committed to the storage system
     61Writing remote contents
     62
     63# Custom storage systems can be created to customize behavior
     64
     65>>> class CustomStorage(FileSystemStorage):
     66...     def get_available_name(self, name):
     67...         # Append numbers to duplicate files rather than underscores, like Trac
     68...
     69...         parts = name.split('.')
     70...         basename, ext = parts[0], parts[1:]
     71...         number = 2
     72...
     73...         while self.exists(name):
     74...             name = '.'.join([basename, str(number)] + ext)
     75...             number += 1
     76...
     77...         return name
     78>>> custom_storage = CustomStorage(tempfile.gettempdir())
     79
     80>>> first = custom_storage.save('custom_storage', ContentFile('custom contents'))
     81>>> first
     82u'custom_storage'
     83>>> second = custom_storage.save('custom_storage', ContentFile('more contents'))
     84>>> second
     85u'custom_storage.2'
     86
     87>>> custom_storage.delete(first)
     88>>> custom_storage.delete(second)
     89"""
Back to Top