你好,游客 登录
背景:
阅读新闻

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

[日期:2017-08-31] 来源:Python_博客园   作者: [字体: ]

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

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

收藏 推荐 打印 | 录入:Cstor | 阅读:
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款
热门评论