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中List.index()方法的使用教程
May 20 Python
Python 实现简单的电话本功能
Aug 09 Python
python使用正则表达式的search()函数实现指定位置搜索功能
Nov 10 Python
Python实现的插入排序算法原理与用法实例分析
Nov 22 Python
Python学习_几种存取xls/xlsx文件的方法总结
May 03 Python
详解Python 解压缩文件
Apr 09 Python
python 经典数字滤波实例
Dec 16 Python
Python函数的返回值、匿名函数lambda、filter函数、map函数、reduce函数用法实例分析
Dec 26 Python
Python语言异常处理测试过程解析
Jan 08 Python
tensorflow多维张量计算实例
Feb 11 Python
python实现梯度下降法
Mar 24 Python
python读取mysql数据绘制条形图
Mar 25 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中利用substr_replace将指定两位置之间的字符替换为*号
2011/01/27 PHP
php中设置index.php文件为只读的方法
2013/02/06 PHP
PHP解析目录路径的3个函数总结
2014/11/18 PHP
PHP 信号管理知识整理汇总
2017/02/19 PHP
php表单处理操作
2017/11/16 PHP
JS短路原理的应用示例 精简代码的途径
2013/12/13 Javascript
js和jquery如何获取图片真实的宽度和高度
2014/09/28 Javascript
js实现类似菜单风格的TAB选项卡效果代码
2015/08/28 Javascript
Bootstrap项目实战之首页内容介绍(全)
2016/04/25 Javascript
解决拦截器对ajax请求的拦截实例详解
2016/12/21 Javascript
20行JS代码实现粘贴板复制功能
2018/02/06 Javascript
基于Vue中点击组件外关闭组件的实现方法
2018/03/06 Javascript
vue 纯js监听滚动条到底部的实例讲解
2018/09/03 Javascript
小程序调用微信支付的方法
2019/09/26 Javascript
[02:51]DOTA2 Supermajor小组分组对阵抽签仪式
2018/06/01 DOTA
python切换hosts文件代码示例
2013/12/31 Python
python实现的登陆Discuz!论坛通用代码分享
2014/07/11 Python
python实现字典(dict)和字符串(string)的相互转换方法
2017/03/01 Python
使用EduBlock轻松学习Python编程
2018/10/08 Python
Python 迭代,for...in遍历,迭代原理与应用示例
2019/10/12 Python
python错误调试及单元文档测试过程解析
2019/12/19 Python
keras 权重保存和权重载入方式
2020/05/21 Python
CSS3属性box-shadow使用指南
2014/12/09 HTML / CSS
家庭睡衣和家庭用品:Little Blue House
2018/03/18 全球购物
如何通过jdbc调用存储过程
2012/04/19 面试题
车间副主任岗位职责
2013/12/24 职场文书
高一物理教学反思
2014/01/24 职场文书
党员入党表决心的话
2014/03/11 职场文书
会计的岗位职责
2014/03/15 职场文书
投资意向书范本
2014/04/01 职场文书
嘉宾邀请函
2015/01/31 职场文书
2015年母亲节活动总结
2015/02/10 职场文书
2015年法律事务部工作总结
2015/07/27 职场文书
vue3引入highlight.js进行代码高亮的方法实例
2022/04/08 Vue.js
MongoDB数据库之添删改查
2022/04/26 MongoDB