summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-07-16 10:41:20 +0200
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-07-24 14:58:57 +0200
commite42defb63b765b589fb8ef54e2d6773999d41939 (patch)
tree2c7bf232debff8f4ce74713658738272e3a97b6b /django
parente5d2664908164d51d2daa46e375da8b6a93def03 (diff)
[5.1.x] Fixed #35604, Refs #35326 -- Made FileSystemStorage.exists() behaviour independent from allow_overwrite.
Partially reverts 0b33a3abc2ca7d68a24f6d0772bc2b9fa603744e. Storage.exists(name) was documented to "return False if the name is available for a new file." but return True if the file exists. This is ambiguous in the overwrite file case. It will now always return whether the file exists. Thank you to Natalia Bidart and Josh Schneier for the review. Backport of 8d6a20b656ff3fa18e36954668a44a831c2f6ddd from main.
Diffstat (limited to 'django')
-rw-r--r--django/core/files/storage/base.py10
-rw-r--r--django/core/files/storage/filesystem.py19
2 files changed, 18 insertions, 11 deletions
diff --git a/django/core/files/storage/base.py b/django/core/files/storage/base.py
index 55285bc23a..31ecbd209a 100644
--- a/django/core/files/storage/base.py
+++ b/django/core/files/storage/base.py
@@ -51,6 +51,10 @@ class Storage:
validate_file_name(name, allow_relative_path=True)
return name
+ def is_name_available(self, name, max_length=None):
+ exceeds_max_length = max_length and len(name) > max_length
+ return not self.exists(name) and not exceeds_max_length
+
# These methods are part of the public API, with default implementations.
def get_valid_name(self, name):
@@ -82,11 +86,11 @@ class Storage:
validate_file_name(file_name)
file_ext = "".join(pathlib.PurePath(file_name).suffixes)
file_root = file_name.removesuffix(file_ext)
- # If the filename already exists, generate an alternative filename
- # until it doesn't exist.
+ # If the filename is not available, generate an alternative
+ # filename until one is available.
# 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):
+ while not self.is_name_available(name, max_length=max_length):
# file_ext includes the dot.
name = os.path.join(
dir_name, self.get_alternative_name(file_root, file_ext)
diff --git a/django/core/files/storage/filesystem.py b/django/core/files/storage/filesystem.py
index ed752cc062..310a0ed0de 100644
--- a/django/core/files/storage/filesystem.py
+++ b/django/core/files/storage/filesystem.py
@@ -4,7 +4,6 @@ from datetime import datetime, timezone
from urllib.parse import urljoin
from django.conf import settings
-from django.core.exceptions import SuspiciousFileOperation
from django.core.files import File, locks
from django.core.files.move import file_move_safe
from django.core.signals import setting_changed
@@ -192,14 +191,18 @@ class FileSystemStorage(Storage, StorageSettingsMixin):
# concurrently.
pass
- def exists(self, name):
- try:
- exists = os.path.lexists(self.path(name))
- except SuspiciousFileOperation:
- raise
+ def is_name_available(self, name, max_length=None):
+ if self._allow_overwrite:
+ return not (max_length and len(name) > max_length)
+ return super().is_name_available(name, max_length=max_length)
+
+ def get_alternative_name(self, file_root, file_ext):
if self._allow_overwrite:
- return False
- return exists
+ return f"{file_root}{file_ext}"
+ return super().get_alternative_name(file_root, file_ext)
+
+ def exists(self, name):
+ return os.path.lexists(self.path(name))
def listdir(self, path):
path = self.path(path)