Django默认使用的文件存储系统

Django的默认文件存储系统是FileSystemStorage,它基于MEDIA_ROOT和MEDIA_URL设置。FileSystemStorage允许自定义存储路径,确保目录存在并设置相应权限。文件创建时考虑文件名冲突,并根据权限模式调整文件权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Django默认使用的文件存储系统’django.core.files.storage.FileSystemStorage’是一个本地存储系统,由settings中的DEFAULT_FILE_STORAGE值确定。
class FileSystemStorage(location=None, base_url=None, file_permissions_mode=None, directory_permissions_mode=None)
FileSystemStorage类继承自Storage类,location是存储文件的绝对路径,默认值是settings中的MEDIA_ROOT值,base_url默认值是settings中的MEDIA_URL值。
当定义location参数时,可以无视MEDIA_ROOT值来存储文件:

from django.db import models
from django.core.files.storage import FileSystemStorage
 
fs = FileSystemStorage(location='/media/photos')
 
class Car(models.Model):
    ...
    photo = models.ImageField(storage=fs)

这样文件会存储在/media/photos文件夹。
可以直接使用Django的文件存储系统来存储文件:

>>> from django.core.files.storage import default_storage
>>> from django.core.files.base 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
可以从FileSystemStorage类的_save方法看下上传文件是怎么存储的:

def _save(self, name, content):
    full_path = self.path(name)
 
    # Create any intermediate directories that do not exist.
    # Note that there is a race between os.path.exists and os.makedirs:
    # if os.makedirs fails with EEXIST, the directory was created
    # concurrently, and we can continue normally. Refs #16082.
    directory = os.path.dirname(full_path)
    if not os.path.exists(directory):
        try:
            if self.directory_permissions_mode is not None:
                # os.makedirs applies the global umask, so we reset it,
                # for consistency with file_permissions_mode behavior.
                old_umask = os.umask(0)
                try:
                    os.makedirs(directory, self.directory_permissions_mode)
                finally:
                    os.umask(old_umask)
            else:
                os.makedirs(directory)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
    if not os.path.isdir(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 os.open 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 os.open!
                fd = os.open(full_path, flags, 0o666)
                _file = None
                try:
                    locks.lock(fd, locks.LOCK_EX)
                    for chunk in content.chunks():
                        if _file is None:
                            mode = 'wb' if isinstance(chunk, bytes) else 'wt'
                            _file = os.fdopen(fd, mode)
                        _file.write(chunk)
                finally:
                    locks.unlock(fd)
                    if _file is not None:
                        _file.close()
                    else:
                        os.close(fd)
        except OSError as e:
            if e.errno == errno.EEXIST:
                # Ooops, the file exists. We need a new file name.
                name = self.get_available_name(name)
                full_path = self.path(name)
            else:
                raise
        else:
            # OK, the file save worked. Break out of the loop.
            break
 
    if self.file_permissions_mode is not None:
        os.chmod(full_path, self.file_permissions_mode)
 
    # Store filenames with forward slashes, even on Windows.
    return force_text(name.replace('\\', '/'))

方法中可以看出,先判断文件存储的目录是否存在,如果不存在,使用os.mkdirs()依次创建目录。
根据directory_permissions_mode参数来确定创建的目录的权限,应该为(0777 &~umask)。
然后使用os.open()创建文件,flags参数为(os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, ‘O_BINARY’, 0)),
这样当文件已存在时,则报EEXIST异常,使用get_available_name()方法重新确定文件的名字。
mode为0o666,权限为(0666 &~umask)。
content为FILE对象,如一切正常,使用FILE.chunks()依次将内容写入文件。
最后,根据file_permissions_mode参数,修改创建文件的权限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值