Ticket #5361: filestorage.13.diff

File filestorage.13.diff, 61.9 KB (added by Marty Alchin, 11 years ago)

Fixed a problem when deleting models, updated to r7261

  • django/core/filestorage/__init__.py

     
     1
  • django/core/filestorage/base.py

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

     
     1import os
     2import urlparse
     3
     4from django.conf import settings
     5from django.utils.encoding import force_unicode, smart_str
     6from django.core.filestorage.base import Backend
     7from django.utils.text import force_unicode
     8
     9class FileSystemBackend(Backend):
     10    """Standard filesystem storage"""
     11
     12    def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL):
     13        self.location = os.path.abspath(location)
     14        self.base_url = base_url
     15
     16    def get_absolute_path(self, filename):
     17        return os.path.normpath(os.path.join(self.location, filename))
     18
     19    def get_filesize(self, filename):
     20        return os.path.getsize(self.get_absolute_path(filename))
     21
     22    def get_absolute_url(self, filename):
     23        return urlparse.urljoin(self.base_url, filename).replace('\\', '/')
     24
     25    def open_file(self, filename, mode='rb'):
     26        return open(self.get_absolute_path(filename), mode)
     27
     28    def file_exists(self, filename):
     29        return os.path.exists(self.get_absolute_path(filename))
     30
     31    def save_file(self, filename, raw_contents):
     32        directory = os.path.join(self.location, os.path.dirname(filename))
     33        if not os.path.exists(directory):
     34            os.makedirs(directory)
     35        elif not os.path.isdir(directory):
     36            raise IOError, "%s exists and is not a directory." % directory
     37
     38        filename = self.get_available_filename(filename)
     39
     40        # Write the file to disk.
     41        fp = self.open_file(filename, 'wb')
     42        fp.write(raw_contents)
     43        fp.close()
     44
     45        # Store filenames with forward slashes, even on Windows
     46        return force_unicode(filename.replace('\\', '/'))
     47
     48    def delete_file(self, filename):
     49        file_name = self.get_absolute_path(filename)
     50        # If the file exists, delete it from the filesystem.
     51        if os.path.exists(file_name):
     52            os.remove(file_name)
  • django/core/serializers/base.py

     
    6161        if isinstance(field, models.DateTimeField):
    6262            value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S")
    6363        elif isinstance(field, models.FileField):
    64             value = getattr(obj, "get_%s_url" % field.name, lambda: None)()
     64            try:
     65                value = getattr(obj, field.name).get_absolute_url()
     66            except ValueError:
     67                value = ""
    6568        else:
    6669            value = field.flatten_data(follow=None, obj=obj).get(field.name, "")
    6770        return smart_unicode(value)
  • django/db/models/__init__.py

     
    88from django.db.models.base import Model, AdminOptions
    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

     
    22import django.db.models.manager
    33from django.core import validators
    44from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
    5 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
     5from django.db.models.fields import AutoField, FieldDoesNotExist
    66from django.db.models.fields.related import OneToOneRel, ManyToOneRel
    77from django.db.models.query import delete_objects
    88from django.db.models.options import Options, AdminOptions
     
    1818import types
    1919import sys
    2020import os
     21from warnings import warn
    2122
    2223class ModelBase(type):
    2324    "Metaclass for all models"
     
    371372        return getattr(self, cachename)
    372373
    373374    def _get_FIELD_filename(self, field):
    374         if getattr(self, field.attname): # value is not blank
    375             return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
    376         return ''
     375        warn("Use instance.%s.get_absolute_path()." % field.attname, DeprecationWarning)
     376        try:
     377            return getattr(self, field.attname).get_absolute_path()
     378        except ValueError:
     379            # For backward compatibility
     380            return settings.MEDIA_ROOT
    377381
    378382    def _get_FIELD_url(self, field):
    379         if getattr(self, field.attname): # value is not blank
    380             import urlparse
    381             return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
    382         return ''
     383        warn("Use instance.%s.get_absolute_url()." % field.attname, DeprecationWarning)
     384        try:
     385            return getattr(self, field.attname).get_absolute_url()
     386        except ValueError:
     387            # For backward compatibility
     388            return settings.MEDIA_URL
    383389
    384390    def _get_FIELD_size(self, field):
    385         return os.path.getsize(self._get_FIELD_filename(field))
     391        warn("Use instance.%s.get_filesize()." % field.attname, DeprecationWarning)
     392        return getattr(self, field.attname).get_filesize()
    386393
    387394    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
    388         directory = field.get_directory_name()
    389         try: # Create the date-based directory if it doesn't exist.
    390             os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
    391         except OSError: # Directory probably already exists.
    392             pass
    393         filename = field.get_filename(filename)
     395        warn("Use instance.%s.save_file()." % field.attname, DeprecationWarning)
     396        return getattr(self, field.attname).save_file(filename, raw_contents, save)
    394397
    395         # If the filename already exists, keep adding an underscore to the name of
    396         # the file until the filename doesn't exist.
    397         while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
    398             try:
    399                 dot_index = filename.rindex('.')
    400             except ValueError: # filename has no dot
    401                 filename += '_'
    402             else:
    403                 filename = filename[:dot_index] + '_' + filename[dot_index:]
    404 
    405         # Write the file to disk.
    406         setattr(self, field.attname, filename)
    407 
    408         full_filename = self._get_FIELD_filename(field)
    409         fp = open(full_filename, 'wb')
    410         fp.write(raw_contents)
    411         fp.close()
    412 
    413         # Save the width and/or height, if applicable.
    414         if isinstance(field, ImageField) and (field.width_field or field.height_field):
    415             from django.utils.images import get_image_dimensions
    416             width, height = get_image_dimensions(full_filename)
    417             if field.width_field:
    418                 setattr(self, field.width_field, width)
    419             if field.height_field:
    420                 setattr(self, field.height_field, height)
    421 
    422         # Save the object because it has changed unless save is False
    423         if save:
    424             self.save()
    425 
    426     _save_FIELD_file.alters_data = True
    427 
    428398    def _get_FIELD_width(self, field):
    429         return self._get_image_dimensions(field)[0]
     399        warn("Use instance.%s.get_width()." % field.attname, DeprecationWarning)
     400        return getattr(self, field.attname).get_width()
    430401
    431402    def _get_FIELD_height(self, field):
    432         return self._get_image_dimensions(field)[1]
     403        warn("Use instance.%s.get_height()." % field.attname, DeprecationWarning)
     404        return getattr(self, field.attname).get_height()
    433405
    434     def _get_image_dimensions(self, field):
    435         cachename = "__%s_dimensions_cache" % field.name
    436         if not hasattr(self, cachename):
    437             from django.utils.images import get_image_dimensions
    438             filename = self._get_FIELD_filename(field)
    439             setattr(self, cachename, get_image_dimensions(filename))
    440         return getattr(self, cachename)
    441 
    442406############################################
    443407# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
    444408############################################
  • django/db/models/fields/__init__.py

     
    11import datetime
    2 import os
    32import time
    43try:
    54    import decimal
     
    280279        name_prefix is a prefix to prepend to the "field_name" argument.
    281280        rel is a boolean specifying whether this field is in a related context.
    282281        """
     282        from django.db.models.fields import files
     283
    283284        field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix)
    284285
    285286        # Add the "unique" validator(s).
     
    311312        # If this field is in a related context, check whether any other fields
    312313        # in the related object have core=True. If so, add a validator --
    313314        # RequiredIfOtherFieldsGiven -- to this FormField.
    314         if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):
     315        if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, files.FileField):
    315316            # First, get the core fields, if any.
    316317            core_field_names = []
    317318            for f in opts.fields:
     
    723724        defaults.update(kwargs)
    724725        return super(EmailField, self).formfield(**defaults)
    725726
    726 class FileField(Field):
    727     def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
    728         self.upload_to = upload_to
    729         kwargs['max_length'] = kwargs.get('max_length', 100)
    730         Field.__init__(self, verbose_name, name, **kwargs)
    731 
    732     def get_internal_type(self):
    733         return "FileField"
    734 
    735     def get_db_prep_save(self, value):
    736         "Returns field's value prepared for saving into a database."
    737         # Need to convert UploadedFile objects provided via a form to unicode for database insertion
    738         if value is None:
    739             return None
    740         return unicode(value)
    741 
    742     def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
    743         field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
    744         if not self.blank:
    745             if rel:
    746                 # This validator makes sure FileFields work in a related context.
    747                 class RequiredFileField(object):
    748                     def __init__(self, other_field_names, other_file_field_name):
    749                         self.other_field_names = other_field_names
    750                         self.other_file_field_name = other_file_field_name
    751                         self.always_test = True
    752                     def __call__(self, field_data, all_data):
    753                         if not all_data.get(self.other_file_field_name, False):
    754                             c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
    755                             c(field_data, all_data)
    756                 # First, get the core fields, if any.
    757                 core_field_names = []
    758                 for f in opts.fields:
    759                     if f.core and f != self:
    760                         core_field_names.extend(f.get_manipulator_field_names(name_prefix))
    761                 # Now, if there are any, add the validator to this FormField.
    762                 if core_field_names:
    763                     field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
    764             else:
    765                 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
    766                 v.always_test = True
    767                 field_list[0].validator_list.append(v)
    768                 field_list[0].is_required = field_list[1].is_required = False
    769 
    770         # If the raw path is passed in, validate it's under the MEDIA_ROOT.
    771         def isWithinMediaRoot(field_data, all_data):
    772             f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
    773             if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
    774                 raise validators.ValidationError, _("Enter a valid filename.")
    775         field_list[1].validator_list.append(isWithinMediaRoot)
    776         return field_list
    777 
    778     def contribute_to_class(self, cls, name):
    779         super(FileField, self).contribute_to_class(cls, name)
    780         setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
    781         setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    782         setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    783         setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))
    784         dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
    785 
    786     def delete_file(self, instance):
    787         if getattr(instance, self.attname):
    788             file_name = getattr(instance, 'get_%s_filename' % self.name)()
    789             # If the file exists and no other object of this type references it,
    790             # delete it from the filesystem.
    791             if os.path.exists(file_name) and \
    792                 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}):
    793                 os.remove(file_name)
    794 
    795     def get_manipulator_field_objs(self):
    796         return [oldforms.FileUploadField, oldforms.HiddenField]
    797 
    798     def get_manipulator_field_names(self, name_prefix):
    799         return [name_prefix + self.name + '_file', name_prefix + self.name]
    800 
    801     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    802         upload_field_name = self.get_manipulator_field_names('')[0]
    803         if new_data.get(upload_field_name, False):
    804             func = getattr(new_object, 'save_%s_file' % self.name)
    805             if rel:
    806                 func(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)
    807             else:
    808                 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
    809 
    810     def get_directory_name(self):
    811         return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    812 
    813     def get_filename(self, filename):
    814         from django.utils.text import get_valid_filename
    815         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    816         return os.path.normpath(f)
    817 
    818     def save_form_data(self, instance, data):
    819         from django.newforms.fields import UploadedFile
    820         if data and isinstance(data, UploadedFile):
    821             getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
    822 
    823     def formfield(self, **kwargs):
    824         defaults = {'form_class': forms.FileField}
    825         # If a file has been provided previously, then the form doesn't require
    826         # that a new file is provided this time.
    827         # The code to mark the form field as not required is used by
    828         # form_for_instance, but can probably be removed once form_for_instance
    829         # is gone. ModelForm uses a different method to check for an existing file.
    830         if 'initial' in kwargs:
    831             defaults['required'] = False
    832         defaults.update(kwargs)
    833         return super(FileField, self).formfield(**defaults)
    834 
    835727class FilePathField(Field):
    836728    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    837729        self.path, self.match, self.recursive = path, match, recursive
     
    858750        defaults.update(kwargs)
    859751        return super(FloatField, self).formfield(**defaults)
    860752
    861 class ImageField(FileField):
    862     def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
    863         self.width_field, self.height_field = width_field, height_field
    864         FileField.__init__(self, verbose_name, name, **kwargs)
    865 
    866     def get_manipulator_field_objs(self):
    867         return [oldforms.ImageUploadField, oldforms.HiddenField]
    868 
    869     def contribute_to_class(self, cls, name):
    870         super(ImageField, self).contribute_to_class(cls, name)
    871         # Add get_BLAH_width and get_BLAH_height methods, but only if the
    872         # image field doesn't have width and height cache fields.
    873         if not self.width_field:
    874             setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
    875         if not self.height_field:
    876             setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
    877 
    878     def get_internal_type(self):
    879         return "ImageField"
    880 
    881     def save_file(self, new_data, new_object, original_object, change, rel, save=True):
    882         FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
    883         # If the image has height and/or width field(s) and they haven't
    884         # changed, set the width and/or height field(s) back to their original
    885         # values.
    886         if change and (self.width_field or self.height_field) and save:
    887             if self.width_field:
    888                 setattr(new_object, self.width_field, getattr(original_object, self.width_field))
    889             if self.height_field:
    890                 setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    891             new_object.save()
    892 
    893     def formfield(self, **kwargs):
    894         defaults = {'form_class': forms.ImageField}
    895         defaults.update(kwargs)
    896         return super(ImageField, self).formfield(**defaults)
    897 
    898753class IntegerField(Field):
    899754    empty_strings_allowed = False
    900755    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.filestorage.filesystem import FileSystemBackend
     7from django.utils.functional import curry
     8from django.dispatch import dispatcher
     9from django.db.models import signals
     10from django.utils.encoding import force_unicode, smart_str
     11from django.utils.translation import ugettext_lazy, ugettext as _
     12from django import oldforms
     13from django import newforms as forms
     14from django.core import validators
     15
     16class File(object):
     17    def __init__(self, instance, field, filename):
     18        self.instance = instance
     19        self.field = field
     20        self.backend = field.backend
     21        self.filename = filename or u''
     22
     23    def __unicode__(self):
     24        return self.filename or u''
     25
     26    def __repr__(self):
     27        return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
     28
     29    def __nonzero__(self):
     30        return not not self.filename
     31
     32    def __eq__(self, other):
     33        if not self.filename and not other:
     34            # An empty filename should equate to None
     35            return True
     36        return self.filename == other
     37
     38    def get_absolute_path(self):
     39        if not self:
     40            raise ValueError, "The '%s' attribute has no file associated with it." % self.field.name
     41        return self.backend.get_absolute_path(self.filename)
     42
     43    def get_absolute_url(self):
     44        if not self:
     45            raise ValueError, "The '%s' attribute has no file associated with it." % self.field.name
     46        return self.backend.get_absolute_url(self.filename)
     47
     48    def get_filesize(self):
     49        if not self:
     50            raise ValueError, "The '%s' attribute has no file associated with it." % self.field.name
     51        if not hasattr(self, '_filesize'):
     52            self._filesize = self.backend.get_filesize(self.filename)
     53        return self._filesize
     54
     55    def open_file(self, mode='rb'):
     56        if not self:
     57            raise ValueError, "The '%s' attribute has no file associated with it." % self.field.name
     58        return self.backend.open_file(self.filename, mode)
     59
     60    def save_file(self, filename, raw_contents, save=True):
     61        filename = self.field.generate_filename(self.instance, filename)
     62        self.filename = self.backend.save_file(filename, raw_contents)
     63        setattr(self.instance, self.field.name, self.filename)
     64        self._has_file = True
     65
     66        # Update the filesize cache
     67        self._filesize = len(raw_contents)
     68
     69        # Save the object because it has changed, unless save is False
     70        if save:
     71            self.instance.save()
     72
     73    def delete_file(self, save=True):
     74        if not self:
     75            raise ValueError, "The '%s' attribute has no file associated with it." % self.field.name
     76        self.backend.delete_file(self.filename)
     77
     78        self.filename = None
     79        setattr(self.instance, self.field.name, self.filename)
     80
     81        # Delete the filesize cache
     82        if hasattr(self, '_filesize'):
     83            del self._filesize
     84
     85        if save:
     86            self.instance.save()
     87
     88class FileProxy(object):
     89    def __init__(self, field):
     90        self.field = field
     91
     92    def __get__(self, instance=None, owner=None):
     93        if instance is None:
     94            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.name, self.owner.__name__)
     95        return self.field.attr_class(instance, self.field, instance.__dict__[self.field.name])
     96
     97    def __set__(self, instance, value):
     98        instance.__dict__[self.field.name] = value
     99
     100class FileField(Field):
     101    attr_class = File
     102
     103    def __init__(self, verbose_name=None, name=None, upload_to='', backend=None, **kwargs):
     104        for arg in ('core', 'primary_key', 'unique'):
     105            if arg in kwargs:
     106                raise TypeError, "__init__() got an unexpected keyword argument '%s'" % arg
     107        self.backend = backend or FileSystemBackend()
     108
     109        self.upload_to = upload_to
     110        if callable(upload_to):
     111            self.generate_filename = upload_to
     112
     113        kwargs['max_length'] = kwargs.get('max_length', 100)
     114        super(FileField, self).__init__(verbose_name, name, **kwargs)
     115
     116    def get_internal_type(self):
     117        return "FileField"
     118
     119    def get_db_prep_lookup(self, lookup_type, value):
     120        if hasattr(value, 'filename'):
     121            value = value.filename
     122        return super(FileField, self).get_db_prep_lookup(lookup_type, value)
     123
     124    def get_db_prep_save(self, value):
     125        "Returns field's value prepared for saving into a database."
     126        # Need to convert UploadedFile objects provided via a form to unicode for database insertion
     127        if value is None:
     128            return None
     129        return unicode(value.filename)
     130
     131    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     132        field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     133        if not self.blank:
     134            if rel:
     135                # This validator makes sure FileFields work in a related context.
     136                class RequiredFileField(object):
     137                    def __init__(self, other_field_names, other_file_field_name):
     138                        self.other_field_names = other_field_names
     139                        self.other_file_field_name = other_file_field_name
     140                        self.always_test = True
     141                    def __call__(self, field_data, all_data):
     142                        if not all_data.get(self.other_file_field_name, False):
     143                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))
     144                            c(field_data, all_data)
     145                # First, get the core fields, if any.
     146                core_field_names = []
     147                for f in opts.fields:
     148                    if f.core and f != self:
     149                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     150                # Now, if there are any, add the validator to this FormField.
     151                if core_field_names:
     152                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     153            else:
     154                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))
     155                v.always_test = True
     156                field_list[0].validator_list.append(v)
     157                field_list[0].is_required = field_list[1].is_required = False
     158
     159        # If the raw path is passed in, validate it's under the MEDIA_ROOT.
     160        def isWithinMediaRoot(field_data, all_data):
     161            f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))
     162            if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):
     163                raise validators.ValidationError, _("Enter a valid filename.")
     164        field_list[1].validator_list.append(isWithinMediaRoot)
     165        return field_list
     166
     167    def contribute_to_class(self, cls, name):
     168        super(FileField, self).contribute_to_class(cls, name)
     169        setattr(cls, self.name, FileProxy(self))
     170        setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self))
     171        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
     172        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
     173        setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save))
     174        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     175
     176    def delete_file(self, instance, sender):
     177        filename = getattr(instance, self.attname).filename
     178        # If no other object of this type references the file,
     179        # delete it from the backend.
     180        if filename and not sender._default_manager.filter(**{self.name: filename}):
     181            self.backend.delete_file(filename)
     182
     183    def get_manipulator_field_objs(self):
     184        return [oldforms.FileUploadField, oldforms.HiddenField]
     185
     186    def get_manipulator_field_names(self, name_prefix):
     187        return [name_prefix + self.name + '_file', name_prefix + self.name]
     188
     189    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     190        upload_field_name = self.get_manipulator_field_names('')[0]
     191        if new_data.get(upload_field_name, False):
     192            if rel:
     193                field = new_data[upload_field_name][0]
     194            else:
     195                field = new_data[upload_field_name]
     196            filename = self.get_filename(field["filename"])
     197            getattr(new_object, self.attname).save_file(filename, field["content"], save)
     198
     199    def get_directory_name(self):
     200        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
     201
     202    def get_filename(self, filename):
     203        return os.path.normpath(self.backend.get_valid_filename(os.path.basename(filename)))
     204
     205    def generate_filename(self, instance, filename):
     206        return os.path.join(self.get_directory_name(), self.get_filename(filename))
     207
     208    def save_form_data(self, instance, data):
     209        from django.newforms.fields import UploadedFile
     210        if data and isinstance(data, UploadedFile):
     211            getattr(instance, self.attname).save_file(data.filename, data.content, save=False)
     212
     213    def formfield(self, **kwargs):
     214        defaults = {'form_class': forms.FileField}
     215        # If a file has been provided previously, then the form doesn't require
     216        # that a new file is provided this time.
     217        # The code to mark the form field as not required is used by
     218        # form_for_instance, but can probably be removed once form_for_instance
     219        # is gone. ModelForm uses a different method to check for an existing file.
     220        if 'initial' in kwargs:
     221            defaults['required'] = False
     222        defaults.update(kwargs)
     223        return super(FileField, self).formfield(**defaults)
     224
     225class ImageFile(File):
     226    def get_width(self):
     227        return self._get_image_dimensions()[0]
     228
     229    def get_height(self):
     230        return self._get_image_dimensions()[1]
     231
     232    def _get_image_dimensions(self):
     233        if not hasattr(self, '_dimensions_cache'):
     234            from django.utils.images import get_image_dimensions
     235            self._dimensions_cache = get_image_dimensions(self.open_file())
     236        return self._dimensions_cache
     237
     238    def save_file(self, filename, raw_contents, save=True):
     239        super(ImageFile, self).save_file(filename, raw_contents, save)
     240       
     241        # Update the cache for image dimensions
     242        from django.utils.images import get_image_dimensions
     243        from cStringIO import StringIO
     244        self._dimensions_cache = get_image_dimensions(StringIO(raw_contents))
     245
     246    def delete_file(self, save=True):
     247        # Clear the image dimensions cache
     248        del self._dimensions_cache
     249
     250        super(ImageFile, self).delete_file(save)
     251
     252class ImageField(FileField):
     253    attr_class = ImageFile
     254
     255    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
     256        self.width_field, self.height_field = width_field, height_field
     257        FileField.__init__(self, verbose_name, name, **kwargs)
     258
     259    def get_manipulator_field_objs(self):
     260        return [oldforms.ImageUploadField, oldforms.HiddenField]
     261
     262    def contribute_to_class(self, cls, name):
     263        super(ImageField, self).contribute_to_class(cls, name)
     264        # Add get_BLAH_width and get_BLAH_height methods, but only if the
     265        # image field doesn't have width and height cache fields.
     266        if not self.width_field:
     267            setattr(cls, 'get_%s_width' % self.name, curry(cls._get_FIELD_width, field=self))
     268        if not self.height_field:
     269            setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self))
     270
     271    def get_internal_type(self):
     272        return "ImageField"
     273
     274    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     275        # If the image has height and/or width field(s) and they haven't
     276        # changed, set the width and/or height field(s) back to their original
     277        # values.
     278        if self.width_field or self.height_field:
     279            if original_object and not change:
     280                if self.width_field:
     281                    setattr(new_object, self.width_field, getattr(original_object, self.width_field))
     282                if self.height_field:
     283                    setattr(new_object, self.height_field, getattr(original_object, self.height_field))
     284            else:
     285                from cStringIO import StringIO
     286                from django.utils.images import get_image_dimensions
     287
     288                upload_field_name = self.get_manipulator_field_names('')[0]
     289                if rel:
     290                    field = new_data[upload_field_name][0]
     291                else:
     292                    field = new_data[upload_field_name]
     293
     294                # Get the width and height from the raw content to avoid extra
     295                # unnecessary trips to the file backend.
     296                width, height = get_image_dimensions(StringIO(field["content"]))
     297
     298                if self.width_field:
     299                    setattr(new_object, self.width_field, width)
     300                if self.height_field:
     301                    setattr(new_object, self.height_field, height)
     302        FileField.save_file(self, new_data, new_object, original_object, change, rel, save)
     303
     304    def formfield(self, **kwargs):
     305        defaults = {'form_class': forms.ImageField}
     306        defaults.update(kwargs)
     307        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/decorators.py

     
    4141                if result is not None:
    4242                    return result
    4343            if hasattr(middleware, 'process_view'):
    44                 result = middleware.process_view(request, view_func, *args, **kwargs)
     44                result = middleware.process_view(request, view_func, args, kwargs)
    4545                if result is not None:
    4646                    return result
    4747            try:
  • django/utils/images.py

     
    66
    77import ImageFile
    88
    9 def get_image_dimensions(path):
    10     """Returns the (width, height) of an image at a given path."""
     9def get_image_dimensions(file_or_path):
     10    """Returns the (width, height) of an image, given an open file or a path."""
    1111    p = ImageFile.Parser()
    12     fp = open(path, 'rb')
     12    if hasattr(file_or_path, 'read'):
     13        fp = file_or_path
     14    else:
     15        fp = open(file_or_path, 'rb')
    1316    while 1:
    1417        data = fp.read(1024)
    1518        if not data:
  • docs/custom_model_fields.txt

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

     
    18701870get_FOO_filename()
    18711871------------------
    18721872
     1873**Deprecated in Django development version. See `managing files`_ for the new,
     1874preferred method for dealing with files.**
     1875
    18731876For every ``FileField``, the object will have a ``get_FOO_filename()`` method,
    18741877where ``FOO`` is the name of the field. This returns the full filesystem path
    18751878to the file, according to your ``MEDIA_ROOT`` setting.
     
    18801883get_FOO_url()
    18811884-------------
    18821885
     1886**Deprecated in Django development version. See `managing files`_ for the new,
     1887preferred method for dealing with files.**
     1888
    18831889For every ``FileField``, the object will have a ``get_FOO_url()`` method,
    18841890where ``FOO`` is the name of the field. This returns the full URL to the file,
    18851891according to your ``MEDIA_URL`` setting. If the value is blank, this method
     
    18881894get_FOO_size()
    18891895--------------
    18901896
     1897**Deprecated in Django development version. See `managing files`_ for the new,
     1898preferred method for dealing with files.**
     1899
    18911900For every ``FileField``, the object will have a ``get_FOO_size()`` method,
    18921901where ``FOO`` is the name of the field. This returns the size of the file, in
    18931902bytes. (Behind the scenes, it uses ``os.path.getsize``.)
     
    18951904save_FOO_file(filename, raw_contents)
    18961905-------------------------------------
    18971906
     1907**Deprecated in Django development version. See `managing files`_ for the new,
     1908preferred method for dealing with files.**
     1909
    18981910For every ``FileField``, the object will have a ``save_FOO_file()`` method,
    18991911where ``FOO`` is the name of the field. This saves the given file to the
    19001912filesystem, using the given filename. If a file with the given filename already
     
    19041916get_FOO_height() and get_FOO_width()
    19051917------------------------------------
    19061918
     1919**Deprecated in Django development version. See `managing files`_ for the new,
     1920preferred method for dealing with files.**
     1921
    19071922For every ``ImageField``, the object will have ``get_FOO_height()`` and
    19081923``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This
    19091924returns the height (or width) of the image, as an integer, in pixels.
    19101925
     1926.. _`managing files`: ../files/
     1927
    19111928Shortcuts
    19121929=========
    19131930
  • docs/files.txt

     
     1==============
     2Managing files
     3==============
     4
     5When dealing with files, Django provides a number of features to make this task
     6easier and more portable. A backend protocol is available to allow files to be
     7stored in a variety of locations, and a special object is provided to allow
     8models to make use of this protocol, without having to worry about which storage
     9system is being used.
     10
     11Using files in models
     12=====================
     13
     14When accessing a ``FileField`` attached to a model, a special object provides
     15access to the file and information about it.
     16
     17``get_absolute_path()``
     18-----------------------
     19
     20Returns the absolute path to the file's location on a local filesystem. For
     21backends which do not store files locally, this will return `None`.
     22
     23``get_absolute_url()``
     24----------------------
     25
     26Provides a URL where the content of the file can be retrieved. Therefore,
     27returned from this method is suitable for use as the destination of a link to
     28the file.
     29
     30``get_filesize()``
     31------------------
     32
     33Returns the size of the file, as an integer.
     34
     35``open_file(mode='rb')``
     36------------------------
     37
     38Returns an open file object, providing read or write access to the file's
     39contents. The ``mode`` argument allows the same values as Python's standard
     40``open()`` function.
     41
     42``save_file(filename, raw_contents, save=True)``
     43------------------------------------------------
     44
     45Saves a new file with the filename and contents provided. This will not replace
     46the existing file, but will create a new file and update the object to point to
     47it. The optional ``save`` argument dictates whether the model instance will be
     48saved to the database immediately.
     49
     50``get_width() and get_height()``
     51--------------------------------
     52
     53When using an ``ImageField``, these two methods will be available, providing
     54easy access to the dimensions of the image.
     55
     56Example
     57-------
     58
     59Consider the following model, using an ``ImageField`` to store a product photo::
     60
     61    class Product(models.Model):
     62        name = models.CharField(maxlength=255)
     63        price = models.DecimalField(max_digits=5, decimal_places=2)
     64        photo = models.ImageField(upload_to='product_photos')
     65
     66Your views can then use the ``photo`` attribute with the functions described
     67above, as follows::
     68
     69    >>> car = Product.object.get(name="'57 Chevy")
     70    >>> car.photo.get_absolute_url()
     71    '/products/photo/123.jpg'
     72    >>> car.photo.get_width(), car.photo.get_height()
     73    (800, 600)
     74
     75Using a storage backend with FileField
     76======================================
     77
     78When using a storage backend, supply whatever options are appropriate for
     79that backend when creating a new object. Details on the requirements for the
     80included backends can be found below. Then pass that object as the ``backend``
     81argument to a ``FileField``.
     82
     83If using the ``FileSystemBackend``, it is not necessary to create a backend
     84object explicitly. Simply supplying the ``upload_to`` argument will create the
     85backend object automatically.
     86
     87See the ```FileField`` documentation`_ for more information on using the field.
     88
     89.. _FileField documentation: ../model-api/#filefield
     90
     91For example, the following code will explicitly use the ``FileSystemBackend``::
     92
     93    from django.db import models
     94    from django.core.filestorage.filesystem import FileSystemBackend
     95   
     96    fs = FileSystemBackend(location='product_photos')
     97   
     98    class Product(models.Model):
     99        name = models.CharField(maxlength=255)
     100        price = models.DecimalField(max_digits=5, decimal_places=2)
     101        photo = models.ImageField(backend=fs)
     102
     103Using a storage backend on its own
     104==================================
     105
     106Storage backends may also be used directly, without being attached to a model.
     107Simply use the following API on any instantiated backend to access files without
     108having to worry about the underlying storage mechanism.
     109       
     110``file_exists(filename)``
     111-------------------------
     112
     113Returns ``True`` or ``False, indicating whether there is already a file present
     114at the location referenced by``filename``.
     115
     116``open_file(filename, mode='rb')``
     117----------------------------------
     118
     119Returns an open file, or file-like, object to provide access to the contents of
     120the file referenced by ``filename``. The ``mode`` argument allows the same
     121values as Python's standard ``open()`` function.
     122
     123``get_filesize(filename)``
     124--------------------------
     125
     126Returns the total size of the file referenced by ``filename``, as an integer.
     127
     128``get_absolute_url(filename)``
     129------------------------------
     130
     131Returns the URL where the contents of the file referenced by ``filename`` can
     132be accessed.
     133
     134``save_file(filename, raw_contents)``
     135-------------------------------------
     136
     137Saves a new file using the backend-specific storage mechanism, preferably using
     138the name specified. If there already exists a file at the location referenced by
     139``filename``, this may modify the filename as necessary to locate one that is
     140available. Once the file is saved, this method will return the filename where
     141the file was actually stored.
     142
     143``delete_file(filename)``
     144-------------------------
     145
     146Deletes the file referenced by ``filename``. If the file does not already exist,
     147this method will simply return without raising an exception.
     148
     149Available backends
     150==================
     151
     152Only one storage backend is supplied in the official Django distribution, but
     153more may be available elsewhere. If you'd like to use a different backend than
     154the one listed below, see the documentation included with the backend.
     155
     156``django.core.filestorage.filesystem.FileSystemBackend``
     157--------------------------------------------------------
     158
     159This backend stores files on the system's standard filesystem.
     160
     161    ======================  ===================================================
     162    Argument                Description
     163    ======================  ===================================================
     164    ``location``            Required. A local filesystem path that will be
     165                            appended to the ``MEDIA_ROOT`` setting to determine
     166                            the output of the ``get_<fieldname>_url()`` helper
     167                            function.
     168    ``media_root``          Required. Absolute path to the directory that holds
     169                            the files for this backend. If omitted, it will be
     170                            set to the value of your ``MEDIA_ROOT`` setting.
     171    ``media_url``           Optional. URL that serves the files stored in this
     172                            backend. If omitted, it will default to the value
     173                            of your ``MEDIA_URL`` setting.
     174    ======================  ===================================================
     175
     176Writing a storage backend
     177=========================
     178
     179While the default filesystem storage is suitable for most needs, there are many
     180other storage mechanisms that may be used, and situations that will require
     181special processing. In order to use Django in these environments, it's fairly
     182simple to write a new storage backend, creating a wrapper around whatever
     183libraries are used to access your files, or simply customizing method calls on
     184an existing backend.
     185
     186A backend must implement the methods described above, but the built-in backends
     187also define two other methods to assist in the process. When writing a custom
     188backend from scratch, these methods are available on the provided ``Backend``
     189class, living at ``django.core.filestorage.base``, so subclassing it will allow
     190these methods to be available on the custom backend as well. When extending an
     191existing backend, overriding these methods allow a great deal of customization.
     192
     193``get_valid_filename(filename)``
     194--------------------------------
     195
     196Returns a filename suitable for use with the underlying storage system. The
     197``filename`` argument passed to this method is the original filename sent to the
     198server, after having any path information removed. Override this to customize
     199how non-standard characters are converted to safe filenames.
     200
     201The code provided on ``Backend`` retains only alpha-numeric characters, periods
     202and underscores from the original filename, removing everything else.
     203
     204``get_available_filename(filename)``
     205------------------------------------
     206
     207Returns a filename that is available in the storage mechanism, possibly taking
     208the provided filename into account. The ``filename`` argument passed to this
     209method will have already cleaned to a filename valid for the storage system,
     210according to the ``get_valid_filename()`` method described above.
     211
     212The code provided on ``Backend`` simply appends underscores to the filename
     213until it finds one that's available in the destination directory.
     214
     215Opening remote files
     216--------------------
     217
     218When accessing a file stored at a remote location, the object returned by
     219``open_file()`` should function like a standard `file object`_, but to keep
     220network traffic to a minimum, writes to the remote storage system should only
     221occur if actually necessary. To make this task easier, Django provides a class
     222to automate this process.
     223
     224Living at ``django.core.filestorage.base``, the ``RemoteFile`` class simulates
     225a standard Python `file object`_, but can write changes to a remote storage
     226system when application using a function provided by the storage backend.
     227Creating an instance of this object requires three arguments, which are
     228described below.
     229
     230    ======================  ===================================================
     231    Argument                Description
     232    ======================  ===================================================
     233    ``data``                The raw content of the file.
     234    ``mode``                The access mode that was passed to the
     235                            ``open_file()`` method.
     236    ``writer``              A function that will be used to write the contents
     237                            to the backend-specific storage mechanism. The
     238                            function provided here will need to take a single
     239                            argument, which will be the raw content to be
     240                            written to the file.
     241    ======================  ===================================================
     242
     243.. _file object: http://docs.python.org/lib/bltin-file-objects.html
     244
  • docs/model-api.txt

     
    230230``FileField``
    231231~~~~~~~~~~~~~
    232232
    233 A file-upload field. Has one **required** argument:
     233A file-upload field. Has three special arguments, of which the first is
     234**required**:
    234235
    235236    ======================  ===================================================
    236237    Argument                Description
    237238    ======================  ===================================================
    238     ``upload_to``           A local filesystem path that will be appended to
    239                             your ``MEDIA_ROOT`` setting to determine the
    240                             output of the ``get_<fieldname>_url()`` helper
    241                             function.
     239    ``upload_to``           Required. A filesystem-style path that will be
     240                            prepended to the filename before being committed to
     241                            the final storage destination.
     242
     243                            **New in Django development version**
     244
     245                            This may also be a callable, such as a function,
     246                            which will be called to obtain the upload path,
     247                            including the filename. See below for details.
     248
     249    ``backend``             **New in Django development version**
     250
     251                            Optional. A storage backend object, which handles
     252                            the storage and retrieval of your files. See
     253                            `managing files`_ for details on how to provide
     254                            this object.
    242255    ======================  ===================================================
    243256
    244 This path may contain `strftime formatting`_, which will be replaced by the
    245 date/time of the file upload (so that uploaded files don't fill up the given
    246 directory).
     257.. _managing files: ../files/
    247258
     259The ``upload_to`` path may contain `strftime formatting`_, which will be
     260replaced by the date/time of the file upload (so that uploaded files don't fill
     261up the given directory).
     262
     263**New in Django development version**
     264
     265If a callable is provided for the ``upload_to`` argument, that callable must be
     266able to accept two arguments, and return a Unix-style path (with forward
     267slashes) to be passed along to the storage backend. The two arguments that will
     268be passed are:
     269
     270    ======================  ===================================================
     271    Argument                Description
     272    ======================  ===================================================
     273    ``instance``            An instance of the model where the ``FileField`` is
     274                            defined. More specifically, this is the particular
     275                            instance where the current file is being attached.
     276                           
     277                            **Note**: In most cases, this object will not have
     278                            been saved to the database yet, so if it uses the
     279                            default ``AutoField``, *it might not yet have a
     280                            value for its primary key field*.
     281
     282    ``filename``            The filename that was originally given to the file.
     283                            This may or may not be taken into account when
     284                            determining the final destination path.
     285    ======================  ===================================================
     286
    248287The admin represents this field as an ``<input type="file">`` (a file-upload
    249288widget).
    250289
    251 Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few
    252 steps:
     290Using a ``FileField`` or an ``ImageField`` (see below) in a model without a
     291specified backend takes a few steps:
    253292
    254293    1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the
    255294       full path to a directory where you'd like Django to store uploaded
  • tests/modeltests/files/__init__.py

     
     1
  • tests/modeltests/files/models.py

     
     1"""
     242. Storing files according to a custom backend
     3
     4FileField and its variations can take a "backend" argument to specify how and
     5where files should be stored.
     6"""
     7
     8import tempfile
     9
     10from django.db import models
     11from django.core.filestorage.filesystem import FileSystemBackend
     12from django.core.cache import cache
     13
     14temp_dir = tempfile.gettempdir()
     15
     16class CustomBackend(FileSystemBackend):
     17    def get_available_filename(self, filename):
     18        # Append numbers to duplicate files rather than underscores, like Trac
     19
     20        parts = filename.split('.')
     21        basename, ext = parts[0], parts[1:]
     22        number = 2
     23
     24        while self.file_exists(filename):
     25            filename = '.'.join([basename, str(number)] + ext)
     26            number += 1
     27
     28        return filename
     29
     30standard_backend = FileSystemBackend(location=temp_dir)
     31custom_backend = CustomBackend(location=temp_dir)
     32
     33class Storage(models.Model):
     34    def custom_upload_to(self, filename):
     35        return 'foo'
     36
     37    normal = models.FileField(backend=standard_backend, upload_to='tests')
     38    custom = models.FileField(backend=custom_backend, upload_to='tests')
     39    upload = models.FileField(upload_to=custom_upload_to)
     40
     41__test__ = {'API_TESTS':"""
     42# An object without a file has limited functionality
     43
     44>>> obj1 = Storage()
     45>>> obj1.normal
     46<File: >
     47>>> obj1.normal.get_filesize()
     48Traceback (most recent call last):
     49...
     50ValueError: The 'normal' attribute has no file associated with it.
     51
     52# Saving a file enables full functionality
     53
     54>>> obj1.normal.save_file('django_test.txt', 'content')
     55>>> obj1.normal
     56<File: tests/django_test.txt>
     57>>> obj1.normal.get_filesize()
     587
     59>>> obj1.normal.open_file().read()
     60'content'
     61
     62# Save another file with the same name
     63
     64>>> obj2 = Storage()
     65>>> obj2.normal.save_file('django_test.txt', 'more content')
     66>>> obj2.normal
     67<File: tests/django_test_.txt>
     68>>> obj2.normal.get_filesize()
     6912
     70
     71# Custom backends can behave differently
     72
     73>>> obj1.custom.save_file('django_test.txt', 'trac-style filenames')
     74>>> obj1.custom
     75<File: tests/django_test.2.txt>
     76>>> obj2.custom.save_file('django_test.txt', 'another file')
     77>>> obj2.custom
     78<File: tests/django_test.3.txt>
     79
     80# Push the objects into the cache to make sure they pickle properly
     81
     82>>> cache.set('obj1', obj1)
     83>>> cache.set('obj2', obj2)
     84>>> cache.get('obj1').custom
     85<File: tests/django_test.2.txt>
     86>>> cache.get('obj2').custom
     87<File: tests/django_test.3.txt>
     88
     89# Clean up the temporary files
     90
     91>>> obj1.normal.delete_file()
     92>>> obj1.custom.delete_file()
     93>>> obj2.normal.delete_file()
     94>>> obj2.custom.delete_file()
     95"""}
  • tests/modeltests/model_forms/models.py

     
    766766<class 'django.newforms.fields.UploadedFile'>
    767767>>> instance = f.save()
    768768>>> instance.file
    769 u'.../test1.txt'
     769<File: .../test1.txt>
    770770
    771771# Edit an instance that already has the file defined in the model. This will not
    772772# save the file again, but leave it exactly as it is.
     
    775775>>> f.is_valid()
    776776True
    777777>>> f.cleaned_data['file']
    778 u'.../test1.txt'
     778<File: .../test1.txt>
    779779>>> instance = f.save()
    780780>>> instance.file
    781 u'.../test1.txt'
     781<File: .../test1.txt>
    782782
    783783# Delete the current file since this is not done by Django.
    784784
    785 >>> os.unlink(instance.get_file_filename())
     785>>> instance.file.delete_file()
    786786
    787787# Override the file by uploading a new one.
    788788
     
    791791True
    792792>>> instance = f.save()
    793793>>> instance.file
    794 u'.../test2.txt'
     794<File: .../test2.txt>
    795795
    796796>>> instance.delete()
    797797
     
    803803True
    804804>>> instance = f.save()
    805805>>> instance.file
    806 ''
     806<File: >
    807807
    808808>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test3.txt', 'content': 'hello world'}}, instance=instance)
    809809>>> f.is_valid()
    810810True
    811811>>> instance = f.save()
    812812>>> instance.file
    813 u'.../test3.txt'
     813<File: .../test3.txt>
    814814>>> instance.delete()
    815815
    816816# ImageField ###################################################################
     
    832832<class 'django.newforms.fields.UploadedFile'>
    833833>>> instance = f.save()
    834834>>> instance.image
    835 u'.../test.png'
     835<File: .../test.png>
    836836
    837837# Edit an instance that already has the image defined in the model. This will not
    838838# save the image again, but leave it exactly as it is.
     
    841841>>> f.is_valid()
    842842True
    843843>>> f.cleaned_data['image']
    844 u'.../test.png'
     844<File: .../test.png>
    845845>>> instance = f.save()
    846846>>> instance.image
    847 u'.../test.png'
     847<File: .../test.png>
    848848
    849849# Delete the current image since this is not done by Django.
    850850
    851 >>> os.unlink(instance.get_image_filename())
     851>>> instance.image.delete_file()
    852852
    853853# Override the file by uploading a new one.
    854854
     
    857857True
    858858>>> instance = f.save()
    859859>>> instance.image
    860 u'.../test2.png'
     860<File: .../test2.png>
    861861
    862862>>> instance.delete()
    863863
     
    869869True
    870870>>> instance = f.save()
    871871>>> instance.image
    872 ''
     872<File: >
    873873
    874874>>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': {'filename': 'test3.png', 'content': image_data}}, instance=instance)
    875875>>> f.is_valid()
    876876True
    877877>>> instance = f.save()
    878878>>> instance.image
    879 u'.../test3.png'
     879<File: .../test3.png>
    880880>>> instance.delete()
    881881
    882882"""}
  • tests/regressiontests/bug639/tests.py

     
    3939        Make sure to delete the "uploaded" file to avoid clogging /tmp.
    4040        """
    4141        p = Photo.objects.get()
    42         os.unlink(p.get_image_filename())
    43  No newline at end of file
     42        os.unlink(p.image.get_absolute_path())
     43 No newline at end of file
  • tests/regressiontests/serializers_regress/models.py

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

     
    223223#     (pk_obj, 620, DatePKData, datetime.date(2006,6,16)),
    224224#     (pk_obj, 630, DateTimePKData, datetime.datetime(2006,6,16,10,42,37)),
    225225    (pk_obj, 640, EmailPKData, "hovercraft@example.com"),
    226     (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
     226#     (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
    227227    (pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
    228228    (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
    229229    (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
Back to Top