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 sys模块sys.path使用方法示例
Dec 04 Python
Python 列表(List)操作方法详解
Mar 11 Python
Python优化技巧之利用ctypes提高执行速度
Sep 11 Python
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
Sep 06 Python
Pyspider中给爬虫伪造随机请求头的实例
May 07 Python
python实现可视化动态CPU性能监控
Jun 21 Python
Python OpenCV处理图像之图像直方图和反向投影
Jul 10 Python
在python中对变量判断是否为None的三种方法总结
Jan 23 Python
Python实现爬取亚马逊数据并打印出Excel文件操作示例
May 16 Python
使用tqdm显示Python代码执行进度功能
Dec 08 Python
使用Keras实现简单线性回归模型操作
Jun 12 Python
浅谈Python基础之列表那些事儿
May 11 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
隐性调用php程序的方法
2009/03/09 PHP
关于file_get_contents返回为空或函数不可用的解决方案
2013/06/24 PHP
解析:php调用MsSQL存储过程使用内置RETVAL获取过程中的return值
2013/07/03 PHP
ThinkPHP框架整合微信支付之刷卡模式图文详解
2019/04/10 PHP
Mootools 1.2教程 函数
2009/09/15 Javascript
jquery图片上下tab切换效果
2011/03/18 Javascript
JQuery插件Style定制化方法的分析与比较
2012/05/03 Javascript
jQuery 拖动层(在可视区域范围内)
2012/05/24 Javascript
JSON遍历方式实例总结
2015/12/07 Javascript
vue.js移动端tab组件的封装实践实例
2017/06/30 Javascript
AngularJS中下拉框的高级用法示例
2017/10/11 Javascript
Vue利用canvas实现移动端手写板的方法
2018/05/03 Javascript
JavaScript引用类型之基本包装类型实例分析【Boolean、Number和String】
2018/08/09 Javascript
vue 动态绑定背景图片的方法
2018/08/10 Javascript
小程序怎样让wx.navigateBack更好用的方法实现
2019/11/01 Javascript
[01:33:25]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第一场 1月24日
2021/03/11 DOTA
Python 深入理解yield
2008/09/06 Python
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
python求最大连续子数组的和
2018/07/07 Python
浅谈django orm 优化
2018/08/18 Python
Python读取YUV文件,并显示的方法
2018/12/04 Python
使用python Telnet远程登录执行程序的方法
2019/01/26 Python
python集合的创建、添加及删除操作示例
2019/10/08 Python
pytorch 查看cuda 版本方式
2020/06/23 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
Python绘制组合图的示例
2020/09/18 Python
Django框架请求生命周期实现原理
2020/11/13 Python
CSS3 毛玻璃效果
2019/08/14 HTML / CSS
DJI全球:DJI Global
2021/03/15 全球购物
不开辟用于交换数据的临时空间,如何完成字符串的逆序
2012/12/02 面试题
煤矿安全生产责任书
2014/04/15 职场文书
销售团队口号大全
2014/06/06 职场文书
推广普通话标语
2014/06/27 职场文书
银行大堂经理培训心得体会
2016/01/09 职场文书
原来闭幕词是这样写的呀!
2019/07/01 职场文书
Kubernetes中Deployment的升级与回滚
2022/04/01 Servers