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 Django连接MySQL数据库做增删改查
Nov 07 Python
Python自定义scrapy中间模块避免重复采集的方法
Apr 07 Python
python实现教务管理系统
Mar 12 Python
python自动化报告的输出用例详解
May 30 Python
Python分割指定页数的pdf文件方法
Oct 26 Python
python将字符串以utf-8格式保存在txt文件中的方法
Oct 30 Python
利用python和ffmpeg 批量将其他图片转换为.yuv格式的方法
Jan 08 Python
python文档字符串(函数使用说明)使用详解
Jul 30 Python
python中matplotlib条件背景颜色的实现
Sep 02 Python
pycharm激活码快速激活及使用步骤
Mar 12 Python
python实现梯度法 python最速下降法
Mar 24 Python
利用python做数据拟合详情
Nov 17 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
Windows下的PHP5.0安装配制详解
2006/09/05 PHP
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(九)
2014/06/24 PHP
php结合正则批量抓取网页中邮箱地址
2015/05/19 PHP
如何使用GDB调试PHP程序
2015/12/08 PHP
php 微信公众平台开发模式实现多客服的实例代码
2016/11/07 PHP
PHP常量DIRECTORY_SEPARATOR原理及用法解析
2020/11/10 PHP
理解Javascript_03_javascript全局观
2010/10/11 Javascript
Jquery知识点二 jquery下对数组的操作
2011/01/15 Javascript
JS动态获取当前时间,并写到特定的区域
2013/05/03 Javascript
全面解析Bootstrap表单使用方法(表单控件)
2015/11/24 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
Vue.js第二天学习笔记(vue-router)
2016/12/01 Javascript
浅析如何利用angular结合translate为项目实现国际化
2016/12/08 Javascript
JavaScript 引用类型实例详解【数组、对象、严格模式等】
2020/05/13 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
Python使用设计模式中的责任链模式与迭代器模式的示例
2016/03/02 Python
Python字符串格式化输出方法分析
2016/04/13 Python
python3编码问题汇总
2016/09/06 Python
Python算法输出1-9数组形成的结果为100的所有运算式
2017/11/03 Python
python 中如何获取列表的索引
2019/07/02 Python
用Python实现最速下降法求极值的方法
2019/07/10 Python
Python制作简易版小工具之计算天数的实现思路
2020/02/13 Python
pytorch读取图像数据转成opencv格式实例
2020/06/02 Python
python 最简单的实现适配器设计模式的示例
2020/06/30 Python
python接入支付宝的实例操作
2020/07/20 Python
Python 如何实现访问者模式
2020/07/28 Python
Python txt文件常用读写操作代码实例
2020/08/03 Python
python 实现音频叠加的示例
2020/10/29 Python
使用CSS3制作饼状旋转载入效果的实例
2015/06/23 HTML / CSS
浅谈CSS3特性查询(Feature Query: @supports)功能简介
2017/07/31 HTML / CSS
汇智创新科技发展有限公司
2015/12/06 面试题
xxx同志考察材料
2014/02/07 职场文书
小学生自我评价100字(15篇)
2014/09/18 职场文书
销售业务员岗位职责
2015/02/13 职场文书
用Python爬取各大高校并可视化帮弟弟选大学,弟弟直呼牛X
2021/06/11 Python