Ticket #5361: 5361-r8012.diff

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

Lots of changes in this one, check the details below

  • django/conf/global_settings.py

     
    223223# Path to the "jing" executable -- needed to validate XMLFields
    224224JING_PATH = "/usr/bin/jing"
    225225
     226# Default file storage mechanism that holds media.
     227DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
     228
    226229# Absolute path to the directory that holds media.
    227230# Example: "/home/media/media.lawrence.com/"
    228231MEDIA_ROOT = ''
  • django/core/files/__init__.py

     
     1import os
     2
     3from django.core.files.base import File
     4
     5def open(path, mode='rb', storage=None, mixin=None):
     6    """
     7    A more intelligent open() than the one that comes with Python, working with
     8    various storage systems and providing a more fully-featured File object.
     9    """
     10    if storage is None:
     11        # In keeping Python's own open(), if no storage system is supplied, it
     12        # looks in the current directory. Since FileSystemStorage protects from
     13        # access outside of its base location, though, this will prevent access
     14        # to arbitrary file paths.
     15        from django.core.files.storage import FileSystemStorage
     16        if os.path.abspath(path) == path:
     17            # If an absolute path was given, the storage system needs to
     18            # set to the root of the filesystem
     19            location = path.split(os.path.sep)[0] + os.path.sep
     20            storage = FileSystemStorage(location=location)
     21        else:
     22            storage = FileSystemStorage(location='')
     23    return storage.open(path, mode, mixin=mixin)
  • django/core/files/base.py

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

     
     1from StringIO import StringIO
     2
     3class RemoteFile(StringIO):
     4    """Sends files to remote storage automatically, when necessary."""
     5
     6    def __init__(self, data, mode, writer):
     7        self._mode = mode
     8        self._write_to_storage = writer
     9        self._is_dirty = False
     10        StringIO.__init__(self, data)
     11
     12    def write(self, data):
     13        if 'w' not in self._mode:
     14            raise AttributeError("File was opened for read-only access.")
     15        StringIO.write(self, data)
     16        self._is_dirty = True
     17
     18    def close(self):
     19        if self._is_dirty:
     20            self._write_to_storage(self.getvalue())
     21        StringIO.close(self)
  • 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
     11class Storage(object):
     12    """
     13    A base storage class, providing some default behaviors that all other
     14    storage systems can inherit or override, as necessary.
     15    """
     16    def get_valid_filename(self, filename):
     17        return get_valid_filename(filename)
     18
     19    def get_available_filename(self, filename):
     20        # If the filename already exists, keep adding an underscore to the name
     21        # of the file until the filename doesn't exist.
     22        while self.exists(filename):
     23            try:
     24                dot_index = filename.rindex('.')
     25            except ValueError: # filename has no dot
     26                filename += '_'
     27            else:
     28                filename = filename[:dot_index] + '_' + filename[dot_index:]
     29        return filename
     30
     31class FileSystemStorage(Storage):
     32    """
     33    Standard filesystem storage
     34    """
     35
     36    def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL):
     37        self.location = os.path.abspath(location)
     38        self.base_url = base_url
     39
     40    def path(self, name):
     41        try:
     42            path = safe_join(self.location, name)
     43        except ValueError:
     44            raise SuspiciousOperation("Attempted access to '%s' denied." % name)
     45        return os.path.normpath(path)
     46
     47    def size(self, name):
     48        return os.path.getsize(self.path(name))
     49
     50    def url(self, name):
     51        if self.base_url is None:
     52            raise ValueError("This file is not accessible via a URL.")
     53        return urlparse.urljoin(self.base_url, name).replace('\\', '/')
     54
     55    def exists(self, name):
     56        return os.path.exists(self.path(name))
     57
     58    def open(self, name, mode='rb', mixin=None):
     59        file = self._open(name, mode)
     60        if mixin:
     61            file.__class__ = type(mixin.__name__, (mixin, file.__class__), {})
     62        return file
     63
     64    def _open(self, name, mode='rb'):
     65        return File(open(self.path(name), mode))
     66
     67    def save(self, name, content):
     68        # Check for old-style usage. Warn here first since there are multiple
     69        # locations where we need to support both new and old usage.
     70        if isinstance(content, basestring):
     71            import warnings
     72            warnings.warn(
     73                message = "Representing uploaded files as strings is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",
     74                category = DeprecationWarning,
     75                stacklevel = 2
     76            )
     77            from django.core.files.uploadedfile import SimpleUploadedFile
     78            content = SimpleUploadedFile(name, content)
     79
     80        if name is None:
     81            name = content.name
     82        name = self.get_available_filename(name)
     83        full_path = self.path(name)
     84
     85        directory = os.path.dirname(full_path)
     86        if not os.path.exists(directory):
     87            os.makedirs(directory)
     88        elif not os.path.isdir(directory):
     89            raise IOError("%s exists and is not a directory." % directory)
     90
     91        if hasattr(content, 'temporary_file_path'):
     92            # This file has a file path that we can move.
     93            content.close()
     94            file_move_safe(content.temporary_file_path(), full_path)
     95        else:
     96            # This is a normal uploadedfile that we can stream.
     97            fp = open(full_path, 'wb')
     98            locks.lock(fp, locks.LOCK_EX)
     99            for chunk in content.chunks():
     100                fp.write(chunk)
     101            locks.unlock(fp)
     102            fp.close()
     103
     104        # Store filenames with forward slashes, even on Windows
     105        return force_unicode(name.replace('\\', '/'))
     106
     107    def delete(self, name):
     108        filename = self.path(name)
     109        # If the file exists, delete it from the filesystem.
     110        if os.path.exists(filename):
     111            os.remove(filename)
     112
     113def get_storage(import_path):
     114    try:
     115        dot = import_path.rindex('.')
     116    except ValueError:
     117        raise ImproperlyConfigured("%s isn't a storage module." % import_path)
     118    module, classname = import_path[:dot], import_path[dot+1:]
     119    try:
     120        mod = __import__(module, {}, {}, [''])
     121    except ImportError, e:
     122        raise ImproperlyConfigured('Error importing storage module %s: "%s"' % (module, e))
     123    try:
     124        storage_class = getattr(mod, classname)
     125    except AttributeError:
     126        raise ImproperlyConfigured('Storage module "%s" does not define a "%s" class.' % (module, classname))
     127    return storage_class()
     128
     129default_storage = get_storage(settings.DEFAULT_FILE_STORAGE)
  • django/core/files/uploadedfile.py

     
    33"""
    44
    55import os
    6 import tempfile
    76import warnings
    87try:
    98    from cStringIO import StringIO
     
    1110    from StringIO import StringIO
    1211
    1312from django.conf import settings
     13from django.core.files.base import File
    1414
     15import tempfile
     16
    1517__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile')
    1618
    1719# Because we fooled around with it a bunch, UploadedFile has a bunch
     
    3840    else:
    3941        return property(getter, setter)
    4042
    41 class UploadedFile(object):
     43class UploadedFile(File):
    4244    """
    4345    A abstract uploaded file (``TemporaryUploadedFile`` and
    4446    ``InMemoryUploadedFile`` are the built-in concrete subclasses).
     
    7577
    7678    name = property(_get_name, _set_name)
    7779
    78     def chunks(self, chunk_size=None):
    79         """
    80         Read the file and yield chucks of ``chunk_size`` bytes (defaults to
    81         ``UploadedFile.DEFAULT_CHUNK_SIZE``).
    82         """
    83         if not chunk_size:
    84             chunk_size = UploadedFile.DEFAULT_CHUNK_SIZE
    85 
    86         if hasattr(self, 'seek'):
    87             self.seek(0)
    88         # Assume the pointer is at zero...
    89         counter = self.size
    90 
    91         while counter > 0:
    92             yield self.read(chunk_size)
    93             counter -= chunk_size
    94 
    9580    # Deprecated properties
    9681    filename = deprecated_property(old="filename", new="name")
    9782    file_name = deprecated_property(old="file_name", new="name")
     
    10792        return self.read()
    10893    data = property(_get_data)
    10994
    110     def multiple_chunks(self, chunk_size=None):
    111         """
    112         Returns ``True`` if you can expect multiple chunks.
    113 
    114         NB: If a particular file representation is in memory, subclasses should
    115         always return ``False`` -- there's no good reason to read from memory in
    116         chunks.
    117         """
    118         if not chunk_size:
    119             chunk_size = UploadedFile.DEFAULT_CHUNK_SIZE
    120         return self.size > chunk_size
    121 
    12295    # Abstract methods; subclasses *must* define read() and probably should
    12396    # define open/close.
    12497    def read(self, num_bytes=None):
     
    130103    def close(self):
    131104        pass
    132105
    133     def xreadlines(self):
    134         return self
    135 
    136     def readlines(self):
    137         return list(self.xreadlines())
    138 
    139     def __iter__(self):
    140         # Iterate over this file-like object by newlines
    141         buffer_ = None
    142         for chunk in self.chunks():
    143             chunk_buffer = StringIO(chunk)
    144 
    145             for line in chunk_buffer:
    146                 if buffer_:
    147                     line = buffer_ + line
    148                     buffer_ = None
    149 
    150                 # If this is the end of a line, yield
    151                 # otherwise, wait for the next round
    152                 if line[-1] in ('\n', '\r'):
    153                     yield line
    154                 else:
    155                     buffer_ = line
    156 
    157         if buffer_ is not None:
    158             yield buffer_
    159 
    160106    # Backwards-compatible support for uploaded-files-as-dictionaries.
    161107    def __getitem__(self, key):
    162108        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
    1314from django.utils.functional import curry
  • 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, FieldDoesNotExist
     16from django.db.models.fields import AutoField, FieldDoesNotExist
    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
     
    458459        return getattr(self, cachename)
    459460
    460461    def _get_FIELD_filename(self, field):
    461         if getattr(self, field.attname): # Value is not blank.
    462             return os.path.normpath(os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname)))
    463         return ''
     462        warn("instance.get_%s_filename() is deprecated. Use instance.%s.path instead." % \
     463            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     464        try:
     465            return getattr(self, field.attname).path
     466        except ValueError:
     467            return ''
    464468
    465469    def _get_FIELD_url(self, field):
    466         if getattr(self, field.attname): # Value is not blank.
    467             import urlparse
    468             return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
    469         return ''
     470        warn("instance.get_%s_url() is deprecated. Use instance.%s.url instead." % \
     471            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     472        try:
     473            return getattr(self, field.attname).url
     474        except ValueError:
     475            return ''
    470476
    471477    def _get_FIELD_size(self, field):
    472         return os.path.getsize(self._get_FIELD_filename(field))
     478        warn("instance.get_%s_size() is deprecated. Use instance.%s.size instead." % \
     479            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     480        return getattr(self, field.attname).size
    473481
    474     def _save_FIELD_file(self, field, filename, raw_field, save=True):
    475         # Create the upload directory if it doesn't already exist
    476         directory = os.path.join(settings.MEDIA_ROOT, field.get_directory_name())
    477         if not os.path.exists(directory):
    478             os.makedirs(directory)
    479         elif not os.path.isdir(directory):
    480             raise IOError('%s exists and is not a directory' % directory)       
     482    def _save_FIELD_file(self, field, filename, content, save=True):
     483        warn("instance.save_%s_file() is deprecated. Use instance.%s.save() instead." % \
     484            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     485        return getattr(self, field.attname).save(filename, content, save)
    481486
    482         # Check for old-style usage (files-as-dictionaries). Warn here first
    483         # since there are multiple locations where we need to support both new
    484         # and old usage.
    485         if isinstance(raw_field, dict):
    486             import warnings
    487             warnings.warn(
    488                 message = "Representing uploaded files as dictionaries is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",
    489                 category = DeprecationWarning,
    490                 stacklevel = 2
    491             )
    492             from django.core.files.uploadedfile import SimpleUploadedFile
    493             raw_field = SimpleUploadedFile.from_dict(raw_field)
    494 
    495         elif isinstance(raw_field, basestring):
    496             import warnings
    497             warnings.warn(
    498                 message = "Representing uploaded files as strings is deprecated. Use django.core.files.uploadedfile.SimpleUploadedFile instead.",
    499                 category = DeprecationWarning,
    500                 stacklevel = 2
    501             )
    502             from django.core.files.uploadedfile import SimpleUploadedFile
    503             raw_field = SimpleUploadedFile(filename, raw_field)
    504 
    505         if filename is None:
    506             filename = raw_field.file_name
    507 
    508         filename = field.get_filename(filename)
    509 
    510         # If the filename already exists, keep adding an underscore to the name
    511         # of the file until the filename doesn't exist.
    512         while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
    513             try:
    514                 dot_index = filename.rindex('.')
    515             except ValueError: # filename has no dot.
    516                 filename += '_'
    517             else:
    518                 filename = filename[:dot_index] + '_' + filename[dot_index:]
    519 
    520         # Save the file name on the object and write the file to disk.
    521         setattr(self, field.attname, filename)
    522         full_filename = self._get_FIELD_filename(field)
    523         if hasattr(raw_field, 'temporary_file_path'):
    524             # This file has a file path that we can move.
    525             raw_field.close()
    526             file_move_safe(raw_field.temporary_file_path(), full_filename)
    527         else:
    528             # This is a normal uploadedfile that we can stream.
    529             fp = open(full_filename, 'wb')
    530             locks.lock(fp, locks.LOCK_EX)
    531             for chunk in raw_field.chunks():
    532                 fp.write(chunk)
    533             locks.unlock(fp)
    534             fp.close()
    535 
    536         # Save the width and/or height, if applicable.
    537         if isinstance(field, ImageField) and \
    538                 (field.width_field or field.height_field):
    539             from django.utils.images import get_image_dimensions
    540             width, height = get_image_dimensions(full_filename)
    541             if field.width_field:
    542                 setattr(self, field.width_field, width)
    543             if field.height_field:
    544                 setattr(self, field.height_field, height)
    545 
    546         # Save the object because it has changed, unless save is False.
    547         if save:
    548             self.save()
    549 
    550487    _save_FIELD_file.alters_data = True
    551488
    552489    def _get_FIELD_width(self, field):
    553         return self._get_image_dimensions(field)[0]
     490        warn("instance.get_%s_width() is deprecated. Use instance.%s.width instead." % \
     491            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     492        return getattr(self, field.attname).width()
    554493
    555494    def _get_FIELD_height(self, field):
    556         return self._get_image_dimensions(field)[1]
     495        warn("instance.get_%s_height() is deprecated. Use instance.%s.height instead." % \
     496            (field.attname, field.attname), DeprecationWarning, stacklevel=3)
     497        return getattr(self, field.attname).height()
    557498
    558     def _get_image_dimensions(self, field):
    559         cachename = "__%s_dimensions_cache" % field.name
    560         if not hasattr(self, cachename):
    561             from django.utils.images import get_image_dimensions
    562             filename = self._get_FIELD_filename(field)
    563             setattr(self, cachename, get_image_dimensions(filename))
    564         return getattr(self, cachename)
    565499
    566 
    567500############################################
    568501# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
    569502############################################
  • 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
     
    759758        defaults.update(kwargs)
    760759        return super(EmailField, self).formfield(**defaults)
    761760
    762 class FileField(Field):
    763     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
    764         self.upload_to = upload_to
    765         kwargs['max_length'] = kwargs.get('max_length', 100)
    766         Field.__init__(self, verbose_name, name, **kwargs)
    767 
    768     def get_internal_type(self):
    769         return "FileField"
    770 
    771     def get_db_prep_save(self, value):
    772         "Returns field's value prepared for saving into a database."
    773         # Need to convert UploadedFile objects provided via a form to unicode for database insertion
    774         if hasattr(value, 'name'):
    775             return value.name
    776         elif value is None:
    777             return None
    778         else:
    779             return unicode(value)
    780 
    781     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    782         field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
    783         if not self.blank:
    784             if rel:
    785                 # This validator makes sure FileFields work in a related context.
    786                 class RequiredFileField(object):
    787                     def __init__(self, other_field_names, other_file_field_name):
    788                         self.other_field_names = other_field_names
    789                         self.other_file_field_name = other_file_field_name
    790                         self.always_test = True
    791                     def __call__(self, field_data, all_data):
    792                         if not all_data.get(self.other_file_field_name, False):
    793                             c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
    794                             c(field_data, all_data)
    795                 # First, get the core fields, if any.
    796                 core_field_names = []
    797                 for f in opts.fields:
    798                     if f.core and f != self:
    799                         core_field_names.extend(f.get_manipulator_field_names(name_prefix))
    800                 # Now, if there are any, add the validator to this FormField.
    801                 if core_field_names:
    802                     field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
    803             else:
    804                 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
    805                 v.always_test = True
    806                 field_list[0].validator_list.append(v)
    807                 field_list[0].is_required = field_list[1].is_required = False
    808 
    809         # If the raw path is passed in, validate it's under the MEDIA_ROOT.
    810         def isWithinMediaRoot(field_data, all_data):
    811             f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
    812             if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
    813                 raise validators.ValidationError, _("Enter a valid filename.")
    814         field_list[1].validator_list.append(isWithinMediaRoot)
    815         return field_list
    816 
    817     def contribute_to_class(self, cls, name):
    818         super(FileField, self).contribute_to_class(cls, name)
    819         setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
    820         setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    821         setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    822         setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save))
    823         dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
    824 
    825     def delete_file(self, instance):
    826         if getattr(instance, self.attname):
    827             file_name = getattr(instance, 'get_%s_filename' % self.name)()
    828             # If the file exists and no other object of this type references it,
    829             # delete it from the filesystem.
    830             if os.path.exists(file_name) and \
    831                 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
    832                 os.remove(file_name)
    833 
    834     def get_manipulator_field_objs(self):
    835         return [oldforms.FileUploadField, oldforms.HiddenField]
    836 
    837     def get_manipulator_field_names(self, name_prefix):
    838         return [name_prefix + self.name + '_file', name_prefix + self.name]
    839 
    840     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    841         upload_field_name = self.get_manipulator_field_names('')[0]
    842         if new_data.get(upload_field_name, False):
    843             if rel:
    844                 file = new_data[upload_field_name][0]
    845             else:
    846                 file = new_data[upload_field_name]
    847 
    848             if not file:
    849                 return
    850 
    851             # Backwards-compatible support for files-as-dictionaries.
    852             # We don't need to raise a warning because Model._save_FIELD_file will
    853             # do so for us.
    854             try:
    855                 file_name = file.name
    856             except AttributeError:
    857                 file_name = file['filename']
    858 
    859             func = getattr(new_object, 'save_%s_file' % self.name)
    860             func(file_name, file, save)
    861 
    862     def get_directory_name(self):
    863         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    864 
    865     def get_filename(self, filename):
    866         from django.utils.text import get_valid_filename
    867         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    868         return os.path.normpath(f)
    869 
    870     def save_form_data(self, instance, data):
    871         from django.core.files.uploadedfile import UploadedFile
    872         if data and isinstance(data, UploadedFile):
    873             getattr(instance, "save_%s_file" % self.name)(data.name, data, save=False)
    874 
    875     def formfield(self, **kwargs):
    876         defaults = {'form_class': forms.FileField}
    877         # If a file has been provided previously, then the form doesn't require
    878         # that a new file is provided this time.
    879         # The code to mark the form field as not required is used by
    880         # form_for_instance, but can probably be removed once form_for_instance
    881         # is gone. ModelForm uses a different method to check for an existing file.
    882         if 'initial' in kwargs:
    883             defaults['required'] = False
    884         defaults.update(kwargs)
    885         return super(FileField, self).formfield(**defaults)
    886 
    887761class FilePathField(Field):
    888762    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    889763        self.path, self.match, self.recursive = path, match, recursive
     
    920794        defaults.update(kwargs)
    921795        return super(FloatField, self).formfield(**defaults)
    922796
    923 class ImageField(FileField):
    924     def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
    925         self.width_field, self.height_field = width_field, height_field
    926         FileField.__init__(self, verbose_name, name, **kwargs)
    927 
    928     def get_manipulator_field_objs(self):
    929         return [oldforms.ImageUploadField, oldforms.HiddenField]
    930 
    931     def contribute_to_class(self, cls, name):
    932         super(ImageField, self).contribute_to_class(cls, name)
    933         # Add get_BLAH_width and get_BLAH_height methods, but only if the
    934         # image field doesn't have width and height cache fields.
    935         if not self.width_field:
    936             setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
    937         if not self.height_field:
    938             setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
    939 
    940     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    941         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
    942         # If the image has height and/or width field(s) and they haven't
    943         # changed, set the width and/or height field(s) back to their original
    944         # values.
    945         if change and (self.width_field or self.height_field) and save:
    946             if self.width_field:
    947                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
    948             if self.height_field:
    949                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    950             new_object.save()
    951 
    952     def formfield(self, **kwargs):
    953         defaults = {'form_class': forms.ImageField}
    954         defaults.update(kwargs)
    955         return super(ImageField, self).formfield(**defaults)
    956 
    957797class IntegerField(Field):
    958798    empty_strings_allowed = False
    959799    def get_manipulator_field_objs(self):
  • 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.utils.functional import curry
     10from django.dispatch import dispatcher
     11from django.db.models import signals
     12from django.utils.encoding import force_unicode, smart_str
     13from django.utils.translation import ugettext_lazy, ugettext as _
     14from django import oldforms
     15from django import forms
     16from django.core import validators
     17from django.db.models.loading import cache
     18
     19class FieldFile(File):
     20    def __init__(self, instance, field, name):
     21        self.instance = instance
     22        self.field = field
     23        self.storage = field.storage
     24        self.name = name or u''
     25
     26    def __eq__(self, other):
     27        # Older code may be expecting FileField values to be simple strings.
     28        # By overriding the == operator, it can remain backwards compatibility.
     29        if hasattr(other, 'name'):
     30            return self.name == other.name
     31        return self.name == other
     32
     33    # The standard File contains most of the necessary properties, but
     34    # FieldFiles can be instantiated without a name, so that needs to
     35    # be checked for here.
     36
     37    def _require_file(self):
     38        if not self:
     39            raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)
     40
     41    def _get_file(self):
     42        self._require_file()
     43        if not hasattr(self, '_file'):
     44            self._file = self.storage.open(self.name, 'rb')
     45        return self._file
     46    file = property(_get_file)
     47
     48    def _get_path(self):
     49        self._require_file()
     50        return self.storage.path(self.name)
     51    path = property(_get_path)
     52
     53    def _get_url(self):
     54        self._require_file()
     55        return self.storage.url(self.name)
     56    url = property(_get_url)
     57
     58    def open(self, mode='rb'):
     59        self._require_file()
     60        return super(FieldFile, self).open(mode)
     61
     62    # In addition to the standard File API, FieldFiles have extra methods
     63    # to further manipulate the underlying file, as well as update the
     64    # associated model instance.
     65
     66    def save(self, name, content, save=True):
     67        name = self.field.generate_filename(self.instance, name)
     68        self.name = self.storage.save(name, content)
     69        setattr(self.instance, self.field.name, self.name)
     70
     71        # Update the filesize cache
     72        self._size = len(content)
     73
     74        # Save the object because it has changed, unless save is False
     75        if save:
     76            self.instance.save()
     77
     78    def delete(self, save=True):
     79        self._require_file()
     80        self.storage.delete(self.name)
     81
     82        self.name = None
     83        setattr(self.instance, self.field.name, self.name)
     84
     85        # Delete the filesize cache
     86        if hasattr(self, '_size'):
     87            del self._size
     88
     89        if save:
     90            self.instance.save()
     91
     92class FileDescriptor(object):
     93    def __init__(self, field):
     94        self.field = field
     95
     96    def __get__(self, instance=None, owner=None):
     97        if instance is None:
     98            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.name(self.owner.__name__))
     99        return self.field.attr_class(instance, self.field, instance.__dict__[self.field.name])
     100
     101    def __set__(self, instance, value):
     102        instance.__dict__[self.field.name] = value
     103
     104class FileField(Field):
     105    attr_class = FieldFile
     106
     107    def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
     108        for arg in ('core', 'primary_key', 'unique'):
     109            if arg in kwargs:
     110                raise TypeError("__init__() got an unexpected keyword argument '%s'" % arg)
     111
     112        self.storage = storage or default_storage
     113        self.upload_to = upload_to
     114        if callable(upload_to):
     115            self.generate_filename = upload_to
     116
     117        kwargs['max_length'] = kwargs.get('max_length', 100)
     118        super(FileField, self).__init__(verbose_name, name, **kwargs)
     119
     120    def get_internal_type(self):
     121        return "FileField"
     122
     123    def get_db_prep_lookup(self, lookup_type, value):
     124        if hasattr(value, 'name'):
     125            value = value.name
     126        return super(FileField, self).get_db_prep_lookup(lookup_type, value)
     127
     128    def get_db_prep_save(self, value):
     129        "Returns field's value prepared for saving into a database."
     130        # Need to convert UploadedFile objects provided via a form to unicode for database insertion
     131        if value is None:
     132            return None
     133        return unicode(value.name)
     134
     135    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     136        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     137        if not self.blank:
     138            if rel:
     139                # This validator makes sure FileFields work in a related context.
     140                class RequiredFileField(object):
     141                    def __init__(self, other_field_names, other_file_field_name):
     142                        self.other_field_names = other_field_names
     143                        self.other_file_field_name = other_file_field_name
     144                        self.always_test = True
     145                    def __call__(self, field_data, all_data):
     146                        if not all_data.get(self.other_file_field_name, False):
     147                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
     148                            c(field_data, all_data)
     149                # First, get the core fields, if any.
     150                core_field_names = []
     151                for f in opts.fields:
     152                    if f.core and f != self:
     153                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     154                # Now, if there are any, add the validator to this FormField.
     155                if core_field_names:
     156                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     157            else:
     158                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
     159                v.always_test = True
     160                field_list[0].validator_list.append(v)
     161                field_list[0].is_required = field_list[1].is_required = False
     162
     163        # If the raw path is passed in, validate it's under the MEDIA_ROOT.
     164        def isWithinMediaRoot(field_data, all_data):
     165            f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
     166            if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
     167                raise validators.ValidationError(_("Enter a valid filename."))
     168        field_list[1].validator_list.append(isWithinMediaRoot)
     169        return field_list
     170
     171    def contribute_to_class(self, cls, name):
     172        super(FileField, self).contribute_to_class(cls, name)
     173        setattr(cls, self.name, FileDescriptor(self))
     174        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
     175        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
     176        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
     177        setattr(cls, 'save_%s_file' % self.name, lambda instance, name, content, save=True: instance._save_FIELD_file(self, name, content, save))
     178        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     179
     180    def delete_file(self, instance, sender):
     181        filename = getattr(instance, self.attname).name
     182        # If no other object of this type references the file,
     183        # and it's not the default value for future objects,
     184        # delete it from the backend.
     185        if filename and filename != self.default and \
     186            not sender._default_manager.filter(**{self.name: filename}):
     187                self.storage.delete(filename)
     188
     189    def get_manipulator_field_objs(self):
     190        return [oldforms.FileUploadField, oldforms.HiddenField]
     191
     192    def get_manipulator_field_names(self, name_prefix):
     193        return [name_prefix + self.name + '_file', name_prefix + self.name]
     194
     195    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     196        upload_field_name = self.get_manipulator_field_names('')[0]
     197        if new_data.get(upload_field_name, False):
     198            if rel:
     199                file = new_data[upload_field_name][0]
     200            else:
     201                file = new_data[upload_field_name]
     202
     203            # Backwards-compatible support for files-as-dictionaries.
     204            # We don't need to raise a warning because the storage backend will
     205            # do so for us.
     206            try:
     207                filename = file.name
     208            except AttributeError:
     209                filename = file['filename']
     210            filename = self.get_filename(filename)
     211
     212            getattr(new_object, self.attname).save(filename, file, save)
     213
     214    def get_directory_name(self):
     215        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
     216
     217    def get_filename(self, filename):
     218        return os.path.normpath(self.storage.get_valid_filename(os.path.basename(filename)))
     219
     220    def generate_filename(self, instance, filename):
     221        return os.path.join(self.get_directory_name(), self.get_filename(filename))
     222
     223    def save_form_data(self, instance, data):
     224        from django.core.files.uploadedfile import UploadedFile
     225        if data and isinstance(data, UploadedFile):
     226            getattr(instance, self.name).save(data.name, data, save=False)
     227
     228    def formfield(self, **kwargs):
     229        defaults = {'form_class': forms.FileField}
     230        # If a file has been provided previously, then the form doesn't require
     231        # that a new file is provided this time.
     232        # The code to mark the form field as not required is used by
     233        # form_for_instance, but can probably be removed once form_for_instance
     234        # is gone. ModelForm uses a different method to check for an existing file.
     235        if 'initial' in kwargs:
     236            defaults['required'] = False
     237        defaults.update(kwargs)
     238        return super(FileField, self).formfield(**defaults)
     239
     240class ImageFieldFile(ImageFile, FieldFile):
     241    def save(self, name, content, save=True):
     242        super(ImageFieldFile, self).save(name, content, save)
     243
     244        # Update the cache for image dimensions
     245        from django.core.files.images import get_image_dimensions
     246        if not hasattr(content, 'read'):
     247            content = ContentFile(name, content)
     248        self._dimensions_cache = get_image_dimensions(content)
     249
     250    def delete(self, save=True):
     251        # Clear the image dimensions cache
     252        if hasattr(self, '_dimensions_cache'):
     253            del self._dimensions_cache
     254
     255        super(ImageFieldFile, self).delete(save)
     256
     257class ImageField(FileField):
     258    attr_class = ImageFieldFile
     259
     260    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
     261        self.width_field, self.height_field = width_field, height_field
     262        FileField.__init__(self, verbose_name, name, **kwargs)
     263
     264    def get_manipulator_field_objs(self):
     265        return [oldforms.ImageUploadField, oldforms.HiddenField]
     266
     267    def contribute_to_class(self, cls, name):
     268        super(ImageField, self).contribute_to_class(cls, name)
     269        # Add get_BLAH_width and get_BLAH_height methods, but only if the
     270        # image field doesn't have width and height cache fields.
     271        if not self.width_field:
     272            setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
     273        if not self.height_field:
     274            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
     275
     276    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     277        # If the image has height and/or width field(s) and they haven't
     278        # changed, set the width and/or height field(s) back to their original
     279        # values.
     280        if self.width_field or self.height_field:
     281            if original_object and not change:
     282                if self.width_field:
     283                    setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     284                if self.height_field:
     285                    setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     286            else:
     287                from django.utils.images import get_image_dimensions
     288
     289                upload_field_name = self.get_manipulator_field_names('')[0]
     290                if rel:
     291                    file = new_data[upload_field_name][0]
     292                else:
     293                    file = new_data[upload_field_name]
     294
     295                # Get the width and height from the raw content to avoid extra
     296                # unnecessary trips to the file backend.
     297                width, height = get_image_dimensions(file)
     298
     299                if self.width_field:
     300                    setattr(new_object, self.width_field, width)
     301                if self.height_field:
     302                    setattr(new_object, self.height_field, height)
     303        super(ImageField, self).save_file(new_data, new_object, original_object, change, rel, save)
     304
     305    def formfield(self, **kwargs):
     306        defaults = {'form_class': forms.ImageField}
     307        defaults.update(kwargs)
     308        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)
  • tests/modeltests/files/__init__.py

     
     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    normal = models.FileField(storage=temp_storage, upload_to='tests')
     25    custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
     26    default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
     27
     28__test__ = {'API_TESTS':"""
     29# An object without a file has limited functionality
     30
     31>>> obj1 = Storage()
     32>>> obj1.normal
     33<FieldFile: None>
     34>>> obj1.normal.size
     35Traceback (most recent call last):
     36...
     37ValueError: The 'normal' attribute has no file associated with it.
     38
     39# Saving a file enables full functionality
     40
     41>>> obj1.normal.save('django_test.txt', ContentFile('content'))
     42>>> obj1.normal
     43<FieldFile: tests/django_test.txt>
     44>>> obj1.normal.size
     457
     46>>> obj1.normal.read()
     47'content'
     48
     49# Save another file with the same name
     50
     51>>> obj2 = Storage()
     52>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
     53>>> obj2.normal
     54<FieldFile: tests/django_test_.txt>
     55>>> obj2.normal.size
     5612
     57
     58# Push the objects into the cache to make sure they pickle properly
     59
     60>>> cache.set('obj1', obj1)
     61>>> cache.set('obj2', obj2)
     62>>> cache.get('obj2').normal
     63<FieldFile: tests/django_test_.txt>
     64
     65# Deleting an object deletes the file it uses, if there are no other objects
     66# still using that file
     67
     68>>> obj2.delete()
     69>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
     70>>> obj2.normal
     71<FieldFile: tests/django_test_.txt>
     72
     73# Default values allow an object to access a single file
     74
     75>>> obj3 = Storage.objects.create()
     76>>> obj3.default
     77<FieldFile: tests/default.txt>
     78>>> obj3.default.read()
     79'default content'
     80
     81# But it shouldn't be deleted, even if there are no more objects using it
     82
     83>>> obj3.delete()
     84>>> obj3 = Storage()
     85>>> obj3.default.read()
     86'default content'
     87
     88# Clean up the temporary files
     89
     90>>> obj1.normal.delete()
     91>>> obj2.normal.delete()
     92>>> obj3.default.delete()
     93"""}
  • 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
     
    7174        # If PIL is available, try testing PIL.
    7275        # Otherwise, it's equivalent to TextFile above.
    7376        import Image
    74         image = models.ImageField(upload_to=tempfile.gettempdir())
     77        image = models.ImageField(storage=temp_storage, upload_to='tests')
    7578    except ImportError:
    76         image = models.FileField(upload_to=tempfile.gettempdir())
     79        image = models.FileField(storage=temp_storage, upload_to='tests')
    7780
    7881    def __unicode__(self):
    7982        return self.description
     
    784787
    785788# FileField ###################################################################
    786789
     790# File forms.
     791
    787792>>> class TextFileForm(ModelForm):
    788793...     class Meta:
    789794...         model = TextFile
     
    806811<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    807812>>> instance = f.save()
    808813>>> instance.file
    809 u'...test1.txt'
     814<FieldFile: tests/test1.txt>
    810815
    811 >>> os.unlink(instance.get_file_filename())
     816>>> instance.file.delete()
    812817
    813818>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test1.txt', 'hello world')})
    814819>>> f.is_valid()
     
    817822<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    818823>>> instance = f.save()
    819824>>> instance.file
    820 u'...test1.txt'
     825<FieldFile: tests/test1.txt>
    821826
    822827# Edit an instance that already has the file defined in the model. This will not
    823828# save the file again, but leave it exactly as it is.
     
    826831>>> f.is_valid()
    827832True
    828833>>> f.cleaned_data['file']
    829 u'...test1.txt'
     834<FieldFile: tests/test1.txt>
    830835>>> instance = f.save()
    831836>>> instance.file
    832 u'...test1.txt'
     837<FieldFile: tests/test1.txt>
    833838
    834839# Delete the current file since this is not done by Django.
    835 >>> os.unlink(instance.get_file_filename())
     840>>> instance.file.delete()
    836841
    837842# Override the file by uploading a new one.
    838843
     
    841846True
    842847>>> instance = f.save()
    843848>>> instance.file
    844 u'...test2.txt'
     849<FieldFile: tests/test2.txt>
    845850
    846851# Delete the current file since this is not done by Django.
    847 >>> os.unlink(instance.get_file_filename())
     852>>> instance.file.delete()
    848853
    849854>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test2.txt', 'hello world')})
    850855>>> f.is_valid()
    851856True
    852857>>> instance = f.save()
    853858>>> instance.file
    854 u'...test2.txt'
     859<FieldFile: tests/test2.txt>
    855860
    856861# Delete the current file since this is not done by Django.
    857 >>> os.unlink(instance.get_file_filename())
     862>>> instance.file.delete()
    858863
    859864>>> instance.delete()
    860865
     
    866871True
    867872>>> instance = f.save()
    868873>>> instance.file
    869 ''
     874<FieldFile: None>
    870875
    871876>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')}, instance=instance)
    872877>>> f.is_valid()
    873878True
    874879>>> instance = f.save()
    875880>>> instance.file
    876 u'...test3.txt'
     881<FieldFile: tests/test3.txt>
    877882
    878883# Delete the current file since this is not done by Django.
    879 >>> os.unlink(instance.get_file_filename())
     884>>> instance.file.delete()
    880885>>> instance.delete()
    881886
    882887>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': SimpleUploadedFile('test3.txt', 'hello world')})
     
    884889True
    885890>>> instance = f.save()
    886891>>> instance.file
    887 u'...test3.txt'
     892<FieldFile: tests/test3.txt>
    888893
    889894# Delete the current file since this is not done by Django.
    890 >>> os.unlink(instance.get_file_filename())
     895>>> instance.file.delete()
    891896>>> instance.delete()
    892897
    893898# ImageField ###################################################################
     
    909914<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    910915>>> instance = f.save()
    911916>>> instance.image
    912 u'...test.png'
     917<ImageFieldFile: tests/test.png>
    913918
    914919# Delete the current file since this is not done by Django.
    915 >>> os.unlink(instance.get_image_filename())
     920>>> instance.image.delete()
    916921
    917922>>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
    918923>>> f.is_valid()
     
    921926<class 'django.core.files.uploadedfile.SimpleUploadedFile'>
    922927>>> instance = f.save()
    923928>>> instance.image
    924 u'...test.png'
     929<ImageFieldFile: tests/test.png>
    925930
    926931# Edit an instance that already has the image defined in the model. This will not
    927932# save the image again, but leave it exactly as it is.
     
    930935>>> f.is_valid()
    931936True
    932937>>> f.cleaned_data['image']
    933 u'...test.png'
     938<ImageFieldFile: tests/test.png>
    934939>>> instance = f.save()
    935940>>> instance.image
    936 u'...test.png'
     941<ImageFieldFile: tests/test.png>
    937942
    938943# Delete the current image since this is not done by Django.
    939944
    940 >>> os.unlink(instance.get_image_filename())
     945>>> instance.image.delete()
    941946
    942947# Override the file by uploading a new one.
    943948
     
    946951True
    947952>>> instance = f.save()
    948953>>> instance.image
    949 u'...test2.png'
     954<ImageFieldFile: tests/test2.png>
    950955
    951956# Delete the current file since this is not done by Django.
    952 >>> os.unlink(instance.get_image_filename())
     957>>> instance.image.delete()
    953958>>> instance.delete()
    954959
    955960>>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)})
     
    957962True
    958963>>> instance = f.save()
    959964>>> instance.image
    960 u'...test2.png'
     965<ImageFieldFile: tests/test2.png>
    961966
    962967# Delete the current file since this is not done by Django.
    963 >>> os.unlink(instance.get_image_filename())
     968>>> instance.image.delete()
    964969>>> instance.delete()
    965970
    966971# Test the non-required ImageField
     
    971976True
    972977>>> instance = f.save()
    973978>>> instance.image
    974 ''
     979<ImageFieldFile: None>
    975980
    976981>>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance)
    977982>>> f.is_valid()
    978983True
    979984>>> instance = f.save()
    980985>>> instance.image
    981 u'...test3.png'
     986<ImageFieldFile: tests/test3.png>
    982987
    983988# Delete the current file since this is not done by Django.
    984 >>> os.unlink(instance.get_image_filename())
     989>>> instance.image.delete()
    985990>>> instance.delete()
    986991
    987992>>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)})
     
    989994True
    990995>>> instance = f.save()
    991996>>> instance.image
    992 u'...test3.png'
     997<ImageFieldFile: tests/test3.png>
    993998>>> instance.delete()
    994999
    9951000# Media on a ModelForm ########################################################
  • 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.test import TestCase, client
    1010from django.utils import simplejson
    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/forms/models.py

     
    2929>>> from django.core.files.uploadedfile import SimpleUploadedFile
    3030
    3131# FileModel with unicode filename and data #########################
    32 >>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह')}, auto_id=False)
     32>>> f = FileForm(data={}, files={'file1': SimpleUploadedFile('?????????.txt', '???? ??????? ???? ??? ????????? ?? ??? ?')}, auto_id=False)
    3333>>> f.is_valid()
    3434True
    3535>>> f.cleaned_data
    36 {'file1': <SimpleUploadedFile: 我隻氣墊船裝滿晒鱔.txt (text/plain)>}
     36{'file1': <SimpleUploadedFile: ?????????.txt (text/plain)>}
    3737>>> m = FileModel.objects.create(file=f.cleaned_data['file1'])
    3838
    3939# Boundary conditions on a PostitiveIntegerField #########################
  • 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

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