From a0ca4b5694f43c63ea13ba6908eff2bd53ee7ebb Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Sun, 19 Aug 2018 20:21:57 -0300 Subject: [PATCH] Fixed #29689 -- Improved performance of FileSystemStorage.listdir() and FilePathField with os.scandir(). --- django/core/files/storage.py | 8 ++++---- django/forms/fields.py | 22 +++++++++++----------- tests/staticfiles_tests/storage.py | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/django/core/files/storage.py b/django/core/files/storage.py index b0168186ef..9929e20981 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -309,11 +309,11 @@ class FileSystemStorage(Storage): def listdir(self, path): path = self.path(path) directories, files = [], [] - for entry in os.listdir(path): - if os.path.isdir(os.path.join(path, entry)): - directories.append(entry) + for entry in os.scandir(path): + if entry.is_dir(): + directories.append(entry.name) else: - files.append(entry) + files.append(entry.name) return directories, files def path(self, name): diff --git a/django/forms/fields.py b/django/forms/fields.py index 0f1a352cdc..9cc93a46e1 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -5,6 +5,7 @@ Field classes. import copy import datetime import math +import operator import os import re import uuid @@ -1104,17 +1105,16 @@ class FilePathField(ChoiceField): f = os.path.join(root, f) self.choices.append((f, f.replace(path, "", 1))) else: - try: - for f in sorted(os.listdir(self.path)): - if f == '__pycache__': - continue - full_file = os.path.join(self.path, f) - if (((self.allow_files and os.path.isfile(full_file)) or - (self.allow_folders and os.path.isdir(full_file))) and - (self.match is None or self.match_re.search(f))): - self.choices.append((full_file, f)) - except OSError: - pass + choices = [] + for f in os.scandir(self.path): + if f.name == '__pycache__': + continue + if (((self.allow_files and f.is_file()) or + (self.allow_folders and f.is_dir())) and + (self.match is None or self.match_re.search(f.name))): + choices.append((f.path, f.name)) + choices.sort(key=operator.itemgetter(1)) + self.choices.extend(choices) self.widget.choices = self.choices diff --git a/tests/staticfiles_tests/storage.py b/tests/staticfiles_tests/storage.py index 7a1f72c130..3214a68a00 100644 --- a/tests/staticfiles_tests/storage.py +++ b/tests/staticfiles_tests/storage.py @@ -39,11 +39,11 @@ class PathNotImplementedStorage(storage.Storage): def listdir(self, path): path = self._path(path) directories, files = [], [] - for entry in os.listdir(path): - if os.path.isdir(os.path.join(path, entry)): - directories.append(entry) + for entry in os.scandir(path): + if entry.is_dir(): + directories.append(entry.name) else: - files.append(entry) + files.append(entry.name) return directories, files def delete(self, name):