w8484855@qq.com 发表于 2017-9-3 23:27:03

Django默认存储系统


               本文和大家分享的主要是django文件存储系统中的默认存储系统相关内容,一起来看看吧,希望对大家学习django有所帮助。
Django默认使用的文件存储系统'django.core.files.storage.FileSystemStorage'是一个本地存储系统,由settings中的DEFAULT_FILE_STORAGE值确定。

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


来源:博客园
页: [1]
查看完整版本: Django默认存储系统