Django文件存储(一)默认存储系统

来源:互联网 发布:如何用单片机控制电机 编辑:程序博客网 时间:2024/06/05 06:11

Django默认使用的文件存储系统'django.core.files.storage.FileSystemStorage'是一个本地存储系统,由settings中的DEFAULT_FILE_STORAGE值确定。

class FileSystemStorage(location=Nonebase_url=Nonefile_permissions_mode=Nonedirectory_permissions_mode=None)

FileSystemStorage类继承自Storage类,location是存储文件的绝对路径,默认值是settings中的MEDIA_ROOT值,base_url默认值是settings中的MEDIA_URL值。

当定义location参数时,可以无视MEDIA_ROOT值来存储文件:

from django.db import modelsfrom django.core.files.storage import FileSystemStoragefs = 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参数,修改创建文件的权限。

原创粉丝点击