zoukankan      html  css  js  c++  java
  • Django文件存储(一)默认存储系统

    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 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参数,修改创建文件的权限。

  • 相关阅读:
    diary and html 文本颜色编辑,行距和其它编辑总汇
    bash coding to changeNames
    virtualbox ubuntu 网络连接 以及 连接 secureCRT
    linux 学习6 软件包安装
    linux 学习8 权限管理
    vim 使用2 转载 为了打开方便
    ubuntu
    linux 学习15 16 启动管理,备份和恢复
    linux 学习 14 日志管理
    linux 学习 13 系统管理
  • 原文地址:https://www.cnblogs.com/linxiyue/p/7442232.html
Copyright © 2011-2022 走看看