Loading django/core/files/storage.py +12 −5 Original line number Diff line number Diff line Loading @@ -51,10 +51,7 @@ class Storage(object): content = File(content, name) name = self.get_available_name(name, max_length=max_length) name = self._save(name, content) # Store filenames with forward slashes, even on Windows return force_text(name.replace('\\', '/')) return self._save(name, content) # These methods are part of the public API, with default implementations. Loading Loading @@ -96,6 +93,15 @@ class Storage(object): name = os.path.join(dir_name, "%s_%s%s" % (file_root, get_random_string(7), file_ext)) return name def generate_filename(self, filename): """ Validate the filename by calling get_valid_name() and return a filename to be passed to the save() method. """ # `filename` may include a path as returned by FileField.upload_to. dirname, filename = os.path.split(filename) return os.path.normpath(os.path.join(dirname, self.get_valid_name(filename))) def path(self, name): """ Returns a local filesystem path where the file can be retrieved using Loading Loading @@ -367,7 +373,8 @@ class FileSystemStorage(Storage): if self.file_permissions_mode is not None: os.chmod(full_path, self.file_permissions_mode) return name # Store filenames with forward slashes, even on Windows. return force_text(name.replace('\\', '/')) def delete(self, name): assert name, "The name argument is not allowed to be empty." Loading django/db/models/fields/files.py +24 −7 Original line number Diff line number Diff line import datetime import os import posixpath import warnings from django import forms from django.core import checks Loading @@ -9,6 +11,7 @@ from django.core.files.storage import default_storage from django.db.models import signals from django.db.models.fields import Field from django.utils import six from django.utils.deprecation import RemovedInDjango20Warning from django.utils.encoding import force_str, force_text from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -294,20 +297,34 @@ class FileField(Field): setattr(cls, self.name, self.descriptor_class(self)) def get_directory_name(self): warnings.warn( 'FileField now delegates file name and folder processing to the ' 'storage. get_directory_name() will be removed in Django 2.0.', RemovedInDjango20Warning, stacklevel=2 ) return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to)))) def get_filename(self, filename): warnings.warn( 'FileField now delegates file name and folder processing to the ' 'storage. get_filename() will be removed in Django 2.0.', RemovedInDjango20Warning, stacklevel=2 ) return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename))) def generate_filename(self, instance, filename): # If upload_to is a callable, make sure that the path it returns is # passed through get_valid_name() of the underlying storage. """ Apply (if callable) or prepend (if a string) upload_to to the filename, then delegate further processing of the name to the storage backend. Until the storage layer, all file paths are expected to be Unix style (with forward slashes). """ if callable(self.upload_to): directory_name, filename = os.path.split(self.upload_to(instance, filename)) filename = self.storage.get_valid_name(filename) return os.path.normpath(os.path.join(directory_name, filename)) return os.path.join(self.get_directory_name(), self.get_filename(filename)) filename = self.upload_to(instance, filename) else: dirname = force_text(datetime.datetime.now().strftime(force_str(self.upload_to))) filename = posixpath.join(dirname, filename) return self.storage.generate_filename(filename) def save_form_data(self, instance, data): # Important: None means "no change", other false value means "clear" Loading docs/internals/deprecation.txt +3 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,9 @@ details on these changes. * Support for ``Widget._format_value()`` will be removed. * ``FileField`` methods ``get_directory_name()`` and ``get_filename()`` will be removed. .. _deprecation-removed-in-1.10: 1.10 Loading docs/ref/files/storage.txt +15 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,21 @@ The ``Storage`` class Returns a filename based on the ``name`` parameter that's suitable for use on the target storage system. .. method:: generate_filename(filename) .. versionadded:: 1.10 Validates the ``filename`` by calling :attr:`get_valid_name()` and returns a filename to be passed to the :meth:`save` method. The ``filename`` argument may include a path as returned by :attr:`FileField.upload_to <django.db.models.FileField.upload_to>`. In that case, the path won't be passed to :attr:`get_valid_name()` but will be prepended back to the resulting name. The default implementation uses :mod:`os.path` operations. Override this method if that's not appropriate for your storage. .. method:: listdir(path) Lists the contents of the specified path, returning a 2-tuple of lists; Loading docs/releases/1.10.txt +24 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,10 @@ File Storage timezone-aware ``datetime`` if :setting:`USE_TZ` is ``True`` and a naive ``datetime`` in the local timezone otherwise. * The new :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>` method makes it easier to implement custom storages that don't use the ``os.path`` calls previously in :class:`~django.db.models.FileField`. File Uploads ~~~~~~~~~~~~ Loading Loading @@ -789,6 +793,21 @@ Miscellaneous * The ``Model._deferred`` attribute is removed as dynamic model classes when using ``QuerySet.defer()`` and ``only()`` is removed. * :meth:`Storage.save() <django.core.files.storage.Storage.save>` no longer replaces ``'\'`` with ``'/'``. This behavior is moved to :class:`~django.core.files.storage.FileSystemStorage` since this is a storage specific implementation detail. Any Windows user with a custom storage implementation that relies on this behavior will need to implement it in the custom storage's ``save()`` method. * Private :class:`~django.db.models.FileField` methods ``get_directory_name()`` and ``get_filename()`` are no longer called (and are now deprecated) which is a backwards incompatible change for users overriding those methods on custom fields. To adapt such code, override ``FileField.generate_filename()`` or :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>` instead. It might be possible to use :attr:`~django.db.models.FileField.upload_to` also. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading Loading @@ -998,6 +1017,11 @@ Miscellaneous :meth:`~django.forms.Widget.format_value`. The old name will work through a deprecation period. * Private ``FileField`` methods ``get_directory_name()`` and ``get_filename()`` are deprecated in favor of performing this work in :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>`). .. _removed-features-1.10: Features removed in 1.10 Loading Loading
django/core/files/storage.py +12 −5 Original line number Diff line number Diff line Loading @@ -51,10 +51,7 @@ class Storage(object): content = File(content, name) name = self.get_available_name(name, max_length=max_length) name = self._save(name, content) # Store filenames with forward slashes, even on Windows return force_text(name.replace('\\', '/')) return self._save(name, content) # These methods are part of the public API, with default implementations. Loading Loading @@ -96,6 +93,15 @@ class Storage(object): name = os.path.join(dir_name, "%s_%s%s" % (file_root, get_random_string(7), file_ext)) return name def generate_filename(self, filename): """ Validate the filename by calling get_valid_name() and return a filename to be passed to the save() method. """ # `filename` may include a path as returned by FileField.upload_to. dirname, filename = os.path.split(filename) return os.path.normpath(os.path.join(dirname, self.get_valid_name(filename))) def path(self, name): """ Returns a local filesystem path where the file can be retrieved using Loading Loading @@ -367,7 +373,8 @@ class FileSystemStorage(Storage): if self.file_permissions_mode is not None: os.chmod(full_path, self.file_permissions_mode) return name # Store filenames with forward slashes, even on Windows. return force_text(name.replace('\\', '/')) def delete(self, name): assert name, "The name argument is not allowed to be empty." Loading
django/db/models/fields/files.py +24 −7 Original line number Diff line number Diff line import datetime import os import posixpath import warnings from django import forms from django.core import checks Loading @@ -9,6 +11,7 @@ from django.core.files.storage import default_storage from django.db.models import signals from django.db.models.fields import Field from django.utils import six from django.utils.deprecation import RemovedInDjango20Warning from django.utils.encoding import force_str, force_text from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -294,20 +297,34 @@ class FileField(Field): setattr(cls, self.name, self.descriptor_class(self)) def get_directory_name(self): warnings.warn( 'FileField now delegates file name and folder processing to the ' 'storage. get_directory_name() will be removed in Django 2.0.', RemovedInDjango20Warning, stacklevel=2 ) return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to)))) def get_filename(self, filename): warnings.warn( 'FileField now delegates file name and folder processing to the ' 'storage. get_filename() will be removed in Django 2.0.', RemovedInDjango20Warning, stacklevel=2 ) return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename))) def generate_filename(self, instance, filename): # If upload_to is a callable, make sure that the path it returns is # passed through get_valid_name() of the underlying storage. """ Apply (if callable) or prepend (if a string) upload_to to the filename, then delegate further processing of the name to the storage backend. Until the storage layer, all file paths are expected to be Unix style (with forward slashes). """ if callable(self.upload_to): directory_name, filename = os.path.split(self.upload_to(instance, filename)) filename = self.storage.get_valid_name(filename) return os.path.normpath(os.path.join(directory_name, filename)) return os.path.join(self.get_directory_name(), self.get_filename(filename)) filename = self.upload_to(instance, filename) else: dirname = force_text(datetime.datetime.now().strftime(force_str(self.upload_to))) filename = posixpath.join(dirname, filename) return self.storage.generate_filename(filename) def save_form_data(self, instance, data): # Important: None means "no change", other false value means "clear" Loading
docs/internals/deprecation.txt +3 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,9 @@ details on these changes. * Support for ``Widget._format_value()`` will be removed. * ``FileField`` methods ``get_directory_name()`` and ``get_filename()`` will be removed. .. _deprecation-removed-in-1.10: 1.10 Loading
docs/ref/files/storage.txt +15 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,21 @@ The ``Storage`` class Returns a filename based on the ``name`` parameter that's suitable for use on the target storage system. .. method:: generate_filename(filename) .. versionadded:: 1.10 Validates the ``filename`` by calling :attr:`get_valid_name()` and returns a filename to be passed to the :meth:`save` method. The ``filename`` argument may include a path as returned by :attr:`FileField.upload_to <django.db.models.FileField.upload_to>`. In that case, the path won't be passed to :attr:`get_valid_name()` but will be prepended back to the resulting name. The default implementation uses :mod:`os.path` operations. Override this method if that's not appropriate for your storage. .. method:: listdir(path) Lists the contents of the specified path, returning a 2-tuple of lists; Loading
docs/releases/1.10.txt +24 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,10 @@ File Storage timezone-aware ``datetime`` if :setting:`USE_TZ` is ``True`` and a naive ``datetime`` in the local timezone otherwise. * The new :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>` method makes it easier to implement custom storages that don't use the ``os.path`` calls previously in :class:`~django.db.models.FileField`. File Uploads ~~~~~~~~~~~~ Loading Loading @@ -789,6 +793,21 @@ Miscellaneous * The ``Model._deferred`` attribute is removed as dynamic model classes when using ``QuerySet.defer()`` and ``only()`` is removed. * :meth:`Storage.save() <django.core.files.storage.Storage.save>` no longer replaces ``'\'`` with ``'/'``. This behavior is moved to :class:`~django.core.files.storage.FileSystemStorage` since this is a storage specific implementation detail. Any Windows user with a custom storage implementation that relies on this behavior will need to implement it in the custom storage's ``save()`` method. * Private :class:`~django.db.models.FileField` methods ``get_directory_name()`` and ``get_filename()`` are no longer called (and are now deprecated) which is a backwards incompatible change for users overriding those methods on custom fields. To adapt such code, override ``FileField.generate_filename()`` or :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>` instead. It might be possible to use :attr:`~django.db.models.FileField.upload_to` also. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading Loading @@ -998,6 +1017,11 @@ Miscellaneous :meth:`~django.forms.Widget.format_value`. The old name will work through a deprecation period. * Private ``FileField`` methods ``get_directory_name()`` and ``get_filename()`` are deprecated in favor of performing this work in :meth:`Storage.generate_filename() <django.core.files.storage.Storage.generate_filename>`). .. _removed-features-1.10: Features removed in 1.10 Loading