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实现的简单万年历例子分享
Apr 25 Python
使用python实现拉钩网上的FizzBuzzWhizz问题示例
May 05 Python
python控制台英汉汉英电子词典
Apr 23 Python
Python中特殊函数集锦
Jul 27 Python
Python内存管理方式和垃圾回收算法解析
Nov 11 Python
python+matplotlib绘制饼图散点图实例代码
Jan 20 Python
解决pandas中读取中文名称的csv文件报错的问题
Jul 04 Python
Python中collections模块的基本使用教程
Dec 07 Python
python基于opencv检测程序运行效率
Dec 28 Python
Python 必须了解的5种高级特征
Sep 10 Python
Python进行区间取值案例讲解
Aug 02 Python
Python中itertools库的四个函数介绍
Apr 06 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&java(一)
2006/10/09 PHP
smarty获得当前url的方法分享
2014/02/14 PHP
win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
2018/09/16 PHP
php分享朋友圈的实现代码
2019/02/18 PHP
parseInt parseFloat js字符串转换数字
2010/08/01 Javascript
JavaScript 操作table,可以新增行和列并且隔一行换背景色代码分享
2013/07/05 Javascript
一个简单的动态加载js和css的jquery代码
2014/09/01 Javascript
node.js中的querystring.parse方法使用说明
2014/12/10 Javascript
浅谈javascript中call()、apply()、bind()的用法
2015/04/20 Javascript
BootStrap智能表单实战系列(六)表单编辑页面的数据绑定
2016/06/13 Javascript
javascript 实现动态侧边栏实例详解
2016/11/11 Javascript
jQuery插件FusionCharts实现的3D柱状图效果实例【附demo源码下载】
2017/03/03 Javascript
理解Angular的providers给Http添加默认headers
2017/07/04 Javascript
node+express+ejs使用模版引擎做的一个示例demo
2017/09/18 Javascript
AngularJS ui-router刷新子页面路由的方法
2018/07/23 Javascript
通过扫小程序码实现网站登陆功能
2019/08/22 Javascript
node.js制作一个简单的登录拦截器
2020/02/10 Javascript
Python中函数及默认参数的定义与调用操作实例分析
2017/07/25 Python
Python使用folium excel绘制point
2019/01/03 Python
django echarts饼图数据动态加载的实例
2019/08/12 Python
python监控nginx端口和进程状态
2019/09/06 Python
TensorFlow tf.nn.conv2d实现卷积的方式
2020/01/03 Python
在pycharm中为项目导入anacodna环境的操作方法
2020/02/12 Python
浅谈pytorch torch.backends.cudnn设置作用
2020/02/20 Python
python不到50行代码完成了多张excel合并的实现示例
2020/05/28 Python
Python使用20行代码实现微信聊天机器人
2020/06/05 Python
Python利用Faiss库实现ANN近邻搜索的方法详解
2020/08/03 Python
Python常用数字处理基本操作汇总
2020/09/10 Python
Ibood荷兰:互联网每日最佳在线优惠
2019/02/28 全球购物
Calphalon美国官网:美国顶级锅具品牌
2020/02/05 全球购物
屈臣氏俄罗斯在线商店:Watsons俄罗斯
2020/08/03 全球购物
物业管理毕业生个人的求职信
2013/11/30 职场文书
幼儿园班级工作总结2015
2015/05/25 职场文书
银行工作心得体会范文
2016/01/23 职场文书
Ajax请求超时与网络异常处理图文详解
2021/05/23 Javascript
python中if和elif的区别介绍
2021/11/07 Python