Django文件存储 默认存储系统解析


Posted in Python onAugust 02, 2019

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

Python 相关文章推荐
Python标准库defaultdict模块使用示例
Apr 28 Python
举例讲解Python中字典的合并值相加与异或对比
Jun 04 Python
用Python将IP地址在整型和字符串之间轻松转换
Mar 22 Python
Python自动化开发学习之三级菜单制作
Jul 14 Python
用python编写第一个IDA插件的实例
May 29 Python
解决每次打开pycharm直接进入项目的问题
Oct 28 Python
在python中对变量判断是否为None的三种方法总结
Jan 23 Python
python实现K近邻回归,采用等权重和不等权重的方法
Jan 23 Python
python区块及区块链的开发详解
Jul 03 Python
关于Python形参打包与解包小技巧分享
Aug 24 Python
python 实现让字典的value 成为列表
Dec 16 Python
python统计文章中单词出现次数实例
Feb 27 Python
Django 迁移、操作数据库的方法
Aug 02 #Python
Django用户认证系统 组与权限解析
Aug 02 #Python
python3中eval函数用法使用简介
Aug 02 #Python
Django用户认证系统 Web请求中的认证解析
Aug 02 #Python
Django用户认证系统 User对象解析
Aug 02 #Python
浅谈python3中input输入的使用
Aug 02 #Python
Pycharm连接远程服务器并实现远程调试的实现
Aug 02 #Python
You might like
二次元帅气男生排行榜,只想悄悄收藏系列
2020/03/04 日漫
PHP远程连接MYSQL数据库非常慢的解决方法
2008/07/05 PHP
php批量删除超链接的实现方法
2015/10/19 PHP
php文件上传后端处理小技巧
2016/05/22 PHP
CI框架(ajax分页,全选,反选,不选,批量删除)完整代码详解
2016/11/01 PHP
Javascript hasOwnProperty 方法 & in 关键字
2008/11/26 Javascript
Javascript页面添加到收藏夹的简单方法
2013/08/07 Javascript
在百度知道团队中快速审批新成员的js脚本
2014/02/02 Javascript
简介AngularJS中使用factory和service的方法
2015/06/17 Javascript
使用nvm和nrm优化node.js工作流的方法
2019/01/17 Javascript
JS实现判断有效的数独算法示例
2019/02/25 Javascript
python提取内容关键词的方法
2015/03/16 Python
基于wxpython开发的简单gui计算器实例
2015/05/30 Python
在Pycharm terminal中字体大小设置的方法
2019/01/16 Python
Python with用法:自动关闭文件进程
2019/07/10 Python
用Python抢火车票的简单小程序实现解析
2019/08/14 Python
Python 进程操作之进程间通过队列共享数据,队列Queue简单示例
2019/10/11 Python
Django 5种类型Session使用方法解析
2020/04/29 Python
Python实现手绘图效果实例分享
2020/07/22 Python
Python连接Mysql进行增删改查的示例代码
2020/08/03 Python
Python实现播放和录制声音的功能
2020/08/12 Python
台湾线上百货零售购物平台:friDay购物
2017/08/18 全球购物
全球速卖通:AliExpress(国际版淘宝)
2017/09/20 全球购物
澳大利亚网上买书:Angus & Robertson
2019/07/21 全球购物
应届大学生自荐信格式
2013/09/21 职场文书
最新计算机专业自荐信
2013/10/16 职场文书
3D空间设计学生找工作的自我评价
2013/10/28 职场文书
寄语十八大感言
2014/02/07 职场文书
自荐信的基本格式
2014/02/22 职场文书
天猫某品牌专卖店运营计划书
2014/03/21 职场文书
学校消防安全责任书
2014/07/23 职场文书
大学生档案自我鉴定(2篇)
2014/10/14 职场文书
教师网络培训心得体会
2016/01/09 职场文书
适合后台管理系统开发的12个前端框架(小结)
2021/06/29 Javascript
pandas中关于apply+lambda的应用
2022/02/28 Python
Java实现扫雷游戏详细代码讲解
2022/05/25 Java/Android