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之不要红头文件(1)
Sep 28 Python
python列表操作实例
Jan 14 Python
Python2.x中文乱码问题解决方法
Jun 02 Python
python获得文件创建时间和修改时间的方法
Jun 30 Python
举例讲解Python设计模式编程中对抽象工厂模式的运用
Mar 02 Python
python实现RabbitMQ的消息队列的示例代码
Nov 08 Python
Django-Rest-Framework 权限管理源码浅析(小结)
Nov 12 Python
python 随机生成10位数密码的实现代码
Jun 27 Python
基于python实现从尾到头打印链表
Nov 02 Python
Python 实现训练集、测试集随机划分
Jan 08 Python
Python中的Cookie模块如何使用
Jun 04 Python
Python常用库Numpy进行矩阵运算详解
Jul 21 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与ASP
2006/10/09 PHP
WML,Apache,和 PHP 的介绍
2006/10/09 PHP
在PHP3中实现SESSION的功能(三)
2006/10/09 PHP
PHP异步进程助手async-helper
2018/02/05 PHP
json跟xml的对比分析
2008/06/10 Javascript
js cookies实现简单统计访问次数
2009/11/24 Javascript
javascript suggest效果 自动完成实现代码分享
2012/02/17 Javascript
在JavaScript中处理数组之reverse()方法的使用
2015/06/09 Javascript
JS操作XML实例总结(加载与解析XML文件、字符串)
2015/12/08 Javascript
jquery.validate提示错误信息位置方法
2016/01/22 Javascript
BootStrap智能表单实战系列(八)表单配置json详解
2016/06/13 Javascript
js中字符型和数值型数字的互相转化方法(必看)
2017/04/25 Javascript
vue将对象新增的属性添加到检测序列的方法
2018/02/24 Javascript
vue.js的computed,filter,get,set的用法及区别详解
2018/03/08 Javascript
重新认识vue之事件阻止冒泡的实现
2018/08/02 Javascript
详解用vue2.x版本+adminLTE开源框架搭建后台应用模版
2019/03/15 Javascript
js简单的分页器插件代码实例
2019/09/11 Javascript
Vue.js获取手机系统型号、版本、浏览器类型的示例代码
2020/05/10 Javascript
Python中使用装饰器时需要注意的一些问题
2015/05/11 Python
Python执行时间的计算方法小结
2017/03/17 Python
Python 调用Java实例详解
2017/06/02 Python
python+pyqt实现12306图片验证效果
2017/10/25 Python
numpy中的ndarray方法和属性详解
2019/05/27 Python
用python做游戏的细节详解
2019/06/25 Python
Python for循环搭配else常见问题解决
2020/02/11 Python
python使用列表的最佳方案
2020/08/12 Python
canvas实现圆形进度条动画的示例代码
2017/12/26 HTML / CSS
什么是Connection-oriented Protocol/Connectionless Protocol面向连接的协议/无连接协议
2012/09/06 面试题
用C#语言写出与SQLSERVER访问时的具体过程
2013/04/16 面试题
导游个人求职信范文
2014/03/23 职场文书
积极向上的团队口号
2014/06/06 职场文书
整顿机关作风心得体会
2014/09/10 职场文书
国庆节标语大全
2014/10/08 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
八项规定自查自纠报告及整改措施
2014/10/26 职场文书
安全伴我行主题班会
2015/08/13 职场文书