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 开发者节省时间的10个方法
Oct 02 Python
Python 实现一个颜色色值转换的小工具
Dec 06 Python
Python基于sklearn库的分类算法简单应用示例
Jul 09 Python
Python中按值来获取指定的键
Mar 04 Python
python实时检测键盘输入函数的示例
Jul 17 Python
python web框架Flask实现图形验证码及验证码的动态刷新实例
Oct 14 Python
如何在 Django 模板中输出 "{{"
Jan 24 Python
python GUI库图形界面开发之PyQt5信号与槽基础使用方法与实例
Mar 06 Python
JupyterNotebook 输出窗口的显示效果调整方法
Apr 13 Python
python DES加密与解密及hex输出和bs64格式输出的实现代码
Apr 13 Python
Python基于gevent实现高并发代码实例
May 15 Python
Tensorflow与Keras自适应使用显存方式
Jun 22 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自定义函数call_user_func和call_user_func_array详解
2011/07/14 PHP
mysql总结之explain
2012/02/27 PHP
Yii2实现同时搜索多个字段的方法
2016/08/10 PHP
PHP二维数组去重算法
2016/12/17 PHP
PHP简单实现二维数组赋值与遍历功能示例
2017/10/19 PHP
鼠标图片振动代码
2006/07/06 Javascript
网页javascript精华代码集
2007/01/24 Javascript
Javascript 读书笔记索引贴
2010/01/11 Javascript
JavaScript 构造函数 面相对象学习必备知识
2010/06/09 Javascript
修改jQuery Validation里默认的验证方法
2012/02/14 Javascript
基于JavaScript 下namespace 功能的简单分析
2013/07/05 Javascript
使用jQuery判断IE浏览器版本的代码
2014/06/14 Javascript
js时间日期格式化封装函数
2014/12/02 Javascript
H5手机端多文件上传预览插件
2017/04/21 Javascript
使用Bootstrap打造特色进度条效果
2017/05/02 Javascript
AngularJS入门教程二:在路由中传递参数的方法分析
2017/05/27 Javascript
vue模式history下在iis中配置流程
2019/04/17 Javascript
JQuery样式操作、click事件以及索引值-选项卡应用示例
2019/05/14 jQuery
ES6模板字符串和标签模板的应用实例分析
2019/06/25 Javascript
详解vue+axios给开发环境和生产环境配置不同的接口地址
2019/08/16 Javascript
Vant 中的Toast设置全局的延迟时间操作
2020/11/04 Javascript
Python获取DLL和EXE文件版本号的方法
2015/03/10 Python
python编程实现希尔排序
2017/04/13 Python
numpy实现合并多维矩阵、list的扩展方法
2018/05/08 Python
在Django下测试与调试REST API的方法详解
2019/08/29 Python
python构建指数平滑预测模型示例
2019/11/21 Python
详解Python修复遥感影像条带的两种方式
2020/02/23 Python
Python 实现PS滤镜中的径向模糊特效
2020/12/03 Python
加拿大高尔夫超市:Golf Town
2018/01/12 全球购物
意大利时尚精品店:Nugnes 1920
2020/02/10 全球购物
小学六一儿童节活动方案
2014/08/27 职场文书
我的职业生涯规划:打造自己的运动帝国
2014/09/18 职场文书
家长学校教学计划
2015/01/19 职场文书
MySQL中出现乱码问题的终极解决宝典
2021/05/26 MySQL
MySQL表类型 存储引擎 的选择
2021/11/11 MySQL
GTX1660显卡搭配显示器推荐
2022/04/19 数码科技