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 相关文章推荐
在类Unix系统上开始Python3编程入门
Aug 20 Python
python实现解数独程序代码
Apr 12 Python
Python学生信息管理系统修改版
Mar 13 Python
python控制windows剪贴板,向剪贴板中写入图片的实例
May 31 Python
windows安装TensorFlow和Keras遇到的问题及其解决方法
Jul 10 Python
python pillow模块使用方法详解
Aug 30 Python
Django框架下静态模板的继承操作示例
Nov 08 Python
python实现布隆过滤器及原理解析
Dec 08 Python
python的列表List求均值和中位数实例
Mar 03 Python
Python常用库Numpy进行矩阵运算详解
Jul 21 Python
Python一行代码实现自动发邮件功能
May 30 Python
python库Tsmoothie模块数据平滑化异常点抓取
Jun 10 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
一个图形显示IP的PHP程序代码
2007/10/19 PHP
10个实用的PHP正则表达式汇总
2014/10/23 PHP
IOS 开发之NSDictionary转换成JSON字符串
2017/08/14 PHP
php写入txt乱码的解决方法
2019/09/17 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
linux mint下安装phpstorm2020包括JDK部分的教程详解
2020/09/17 PHP
javascript编程起步(第二课)
2007/01/10 Javascript
动态为事件添加js代码示例
2009/02/15 Javascript
jQuery 学习入门篇附实例代码
2010/03/16 Javascript
Jquery中getJSON在asp.net中的使用说明
2011/03/10 Javascript
js数组Array sort方法使用深入分析
2013/02/21 Javascript
js实现飞入星星特效代码
2014/10/17 Javascript
jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
2015/12/31 Javascript
jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析
2016/10/30 Javascript
angular2路由之routerLinkActive指令【推荐】
2018/05/30 Javascript
详解JavaScript 浮点数运算的精度问题
2019/07/23 Javascript
vue项目中全局引入1个.scss文件的问题解决
2019/08/01 Javascript
Angular6项目打包优化的实现方法
2019/12/15 Javascript
JavaScript实现移动端带transition动画的轮播效果
2020/03/24 Javascript
原生js实现购物车功能
2020/09/23 Javascript
解决Python出现_warn_unsafe_extraction问题的方法
2016/03/24 Python
python+mongodb数据抓取详细介绍
2017/10/25 Python
Python数据结构与算法之字典树实现方法示例
2017/12/13 Python
python实现简单登陆流程的方法
2018/04/22 Python
Python3之读取连接过的网络并定位的方法
2018/04/22 Python
Python3内置模块之json编解码方法小结【推荐】
2020/12/09 Python
python 实现多线程下载m3u8格式视频并使用fmmpeg合并
2019/11/15 Python
Python爬取365好书中小说代码实例
2020/02/28 Python
pytorch 多分类问题,计算百分比操作
2020/07/09 Python
Eagle Eyes Optics鹰眼光学:高性能太阳镜
2018/12/07 全球购物
德国药房apodiscounter中文官网:德国排名前三的网上药店
2019/06/03 全球购物
巧克力蛋糕店创业计划书
2014/01/14 职场文书
班主任师德师风自我剖析材料
2014/10/02 职场文书
构建和谐校园倡议书
2015/01/19 职场文书
自我检讨报告
2015/01/28 职场文书
2016年教师党员承诺书范文
2016/03/24 职场文书