summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryukihira1992 <hirayama@cancerscan.jp>2019-08-29 01:17:07 +0900
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-08-30 11:32:19 +0200
commit05457817647368be4b019314fcc655445a5b4c0c (patch)
tree91ca38fb0ba6a710929fa29fa772cb4cca5e334d
parent400ec5125ec32e3b18d267bbb4f3aab09d741ce4 (diff)
Fixed #30736 -- Added Storage.get_alternative_name() to allow customization.
-rw-r--r--django/core/files/storage.py17
-rw-r--r--docs/howto/custom-file-storage.txt10
-rw-r--r--docs/ref/files/storage.txt11
-rw-r--r--docs/releases/3.0.txt4
4 files changed, 31 insertions, 11 deletions
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index cbdab1de47..4c27fce605 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -60,6 +60,14 @@ class Storage:
"""
return get_valid_filename(name)
+ def get_alternative_name(self, file_root, file_ext):
+ """
+ Return an alternative filename, by adding an underscore and a random 7
+ character alphanumeric string (before the file extension, if one
+ exists) to the filename.
+ """
+ return '%s_%s%s' % (file_root, get_random_string(7), file_ext)
+
def get_available_name(self, name, max_length=None):
"""
Return a filename that's free on the target storage system and
@@ -67,14 +75,13 @@ class Storage:
"""
dir_name, file_name = os.path.split(name)
file_root, file_ext = os.path.splitext(file_name)
- # If the filename already exists, add an underscore and a random 7
- # character alphanumeric string (before the file extension, if one
- # exists) to the filename until the generated filename doesn't exist.
+ # If the filename already exists, generate an alternative filename
+ # until it doesn't exist.
# Truncate original name if required, so the new filename does not
# exceed the max_length.
while self.exists(name) or (max_length and len(name) > max_length):
# file_ext includes the dot.
- name = os.path.join(dir_name, "%s_%s%s" % (file_root, get_random_string(7), file_ext))
+ name = os.path.join(dir_name, self.get_alternative_name(file_root, file_ext))
if max_length is None:
continue
# Truncate file_root if max_length exceeded.
@@ -88,7 +95,7 @@ class Storage:
'Please make sure that the corresponding file field '
'allows sufficient "max_length".' % name
)
- name = os.path.join(dir_name, "%s_%s%s" % (file_root, get_random_string(7), file_ext))
+ name = os.path.join(dir_name, self.get_alternative_name(file_root, file_ext))
return name
def generate_filename(self, filename):
diff --git a/docs/howto/custom-file-storage.txt b/docs/howto/custom-file-storage.txt
index 0ad094da79..d9e18a6003 100644
--- a/docs/howto/custom-file-storage.txt
+++ b/docs/howto/custom-file-storage.txt
@@ -97,6 +97,12 @@ non-standard characters are converted to safe filenames.
The code provided on ``Storage`` retains only alpha-numeric characters, periods
and underscores from the original filename, removing everything else.
+.. method:: get_alternative_name(file_root, file_ext)
+
+Returns an alternative filename based on the ``file_root`` and ``file_ext``
+parameters. By default, an underscore plus a random 7 character alphanumeric
+string is appended to the filename before the extension.
+
.. method:: get_available_name(name, max_length=None)
Returns a filename that is available in the storage mechanism, possibly taking
@@ -108,5 +114,5 @@ The length of the filename will not exceed ``max_length``, if provided. If a
free unique filename cannot be found, a :exc:`SuspiciousFileOperation
<django.core.exceptions.SuspiciousOperation>` exception is raised.
-If a file with ``name`` already exists, an underscore plus a random 7 character
-alphanumeric string is appended to the filename before the extension.
+If a file with ``name`` already exists, ``get_alternative_name()`` is called to
+obtain an alternative name.
diff --git a/docs/ref/files/storage.txt b/docs/ref/files/storage.txt
index 2a82402fac..0724a0cda1 100644
--- a/docs/ref/files/storage.txt
+++ b/docs/ref/files/storage.txt
@@ -105,6 +105,12 @@ The ``Storage`` class
If :setting:`USE_TZ` is ``True``, returns an aware ``datetime``,
otherwise returns a naive ``datetime`` in the local timezone.
+ .. method:: get_alternative_name(file_root, file_ext)
+
+ Returns an alternative filename based on the ``file_root`` and
+ ``file_ext`` parameters, an underscore plus a random 7 character
+ alphanumeric string is appended to the filename before the extension.
+
.. method:: get_available_name(name, max_length=None)
Returns a filename based on the ``name`` parameter that's free and
@@ -116,9 +122,8 @@ The ``Storage`` class
:exc:`SuspiciousFileOperation
<django.core.exceptions.SuspiciousOperation>` exception will be raised.
- If a file with ``name`` already exists, an underscore plus a random
- 7 character alphanumeric string is appended to the filename before
- the extension.
+ If a file with ``name`` already exists, :meth:`get_alternative_name` is
+ called to obtain an alternative name.
.. method:: get_created_time(name)
diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt
index 7a9adb3b39..910d3a2592 100644
--- a/docs/releases/3.0.txt
+++ b/docs/releases/3.0.txt
@@ -227,7 +227,9 @@ Email
File Storage
~~~~~~~~~~~~
-* ...
+* The new :meth:`.Storage.get_alternative_name` method allows customizing the
+ algorithm for generating filenames if a file with the uploaded name already
+ exists.
File Uploads
~~~~~~~~~~~~