The file storage system ''used by Django by default'' is a local storage system, determined by the DEFAULT_FILE_STORAGE value in settings.
class FileSystemStorage(location=None, base_url=None, file_permissions_mode=None, directory_permissions_mode=None)
The FileSystemStorage class inherits from the Storage class. location is the absolute path to the storage file, the default value is the MEDIA_ROOT value in settings, and the default value of base_url is the MEDIA_URL value in settings.
When the location parameter is defined, the MEDIA_ROOT value can be ignored to store the file:
from import models from import FileSystemStorage fs = FileSystemStorage(location='/media/photos') class Car(): ... photo = (storage=fs)
This way the files are stored in the /media/photos folder.
Files can be stored directly using Django's file storage system:
>>> from import default_storage >>> from import ContentFile >>> path = default_storage.save('/path/to/file', ContentFile('new content')) >>> path '/path/to/file' >>> default_storage.size(path) 11 >>> default_storage.open(path).read() 'new content' >>> default_storage.delete(path) >>> default_storage.exists(path) False
You can see how uploaded files are stored from the _save method of the FileSystemStorage class:
def _save(self, name, content): full_path = (name) # Create any intermediate directories that do not exist. # Note that there is a race between and : # if fails with EEXIST, the directory was created # concurrently, and we can continue normally. Refs #16082. directory = (full_path) if not (directory): try: if self.directory_permissions_mode is not None: # applies the global umask, so we reset it, # for consistency with file_permissions_mode behavior. old_umask = (0) try: (directory, self.directory_permissions_mode) finally: (old_umask) else: (directory) except OSError as e: if != : raise if not (directory): raise IOError("%s exists and is not a directory." % directory) # There's a potential race condition between get_available_name and # saving the file; it's possible that two threads might return the # same name, at which point all sorts of fun happens. So we need to # try to create the file, but if it already exists we have to go back # to get_available_name() and try again. while True: try: # This file has a file path that we can move. if hasattr(content, 'temporary_file_path'): file_move_safe(content.temporary_file_path(), full_path) # This is a normal uploadedfile that we can stream. else: # This fun binary flag incantation makes throw an # OSError if the file already exists before we open it. flags = (os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0)) # The current umask value is masked out by ! fd = (full_path, flags, 0o666) _file = None try: (fd, locks.LOCK_EX) for chunk in (): if _file is None: mode = 'wb' if isinstance(chunk, bytes) else 'wt' _file = (fd, mode) _file.write(chunk) finally: (fd) if _file is not None: _file.close() else: (fd) except OSError as e: if == : # Ooops, the file exists. We need a new file name. name = self.get_available_name(name) full_path = (name) else: raise else: # OK, the file save worked. Break out of the loop. break if self.file_permissions_mode is not None: (full_path, self.file_permissions_mode) # Store filenames with forward slashes, even on Windows. return force_text(('\\', '/'))
As you can see in the method, first determine whether the directory in which the file is stored exists, and if it doesn't, use () to create the directory in turn.
Determine the permissions of the created directory based on the directory_permissions_mode parameter, which should be (0777 &~umask).
The file is then created using () with the flags argument (os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0)).
This reports an EEXIST exception when the file already exists, and uses the get_available_name() method to re-establish the name of the file.
The mode is 0o666 and the permissions are (0666 &~umask).
content is a FILE object, if all is well, use () to write the contents to the file in turn.
Finally, modify the permissions of the created file according to the file_permissions_mode parameter.