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脚本实现查找webshell的方法
Jul 31 Python
跟老齐学Python之通过Python连接数据库
Oct 28 Python
Python制作简易注册登录系统
Dec 15 Python
Python中datetime模块参考手册
Jan 13 Python
python构建自定义回调函数详解
Jun 20 Python
ORM Django 终端打印 SQL 语句实现解析
Aug 09 Python
快速查找Python安装路径方法
Feb 06 Python
python连接mongodb集群方法详解
Feb 13 Python
Python调用JavaScript代码的方法
Oct 27 Python
python 从list中随机取值的方法
Nov 16 Python
python 实现Harris角点检测算法
Dec 11 Python
实例讲解Python中sys.argv[]的用法
Jun 03 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中检查PHP文件是否有语法错误的方法
2009/12/23 PHP
PHP调用Webservice实例代码
2011/07/29 PHP
php用正则表达式匹配中文实例详解
2013/11/06 PHP
PHP常用处理静态操作类
2015/04/03 PHP
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
2015/11/15 PHP
php封装的page分页类完整实例
2016/10/18 PHP
php实现的mysqldb读写分离操作类示例
2017/02/07 PHP
js 内存释放问题
2010/04/25 Javascript
jQuery 表单验证扩展(四)
2010/10/20 Javascript
找出字符串中出现次数最多的字母和出现次数精简版
2012/11/07 Javascript
js 与 php 通过json数据进行通讯示例
2014/03/26 Javascript
JS获取及设置TextArea或input文本框选择文本位置的方法
2015/03/24 Javascript
Node.js连接postgreSQL并进行数据操作
2016/12/18 Javascript
JavaScript对象封装的简单实现方法(3种方法)
2017/01/03 Javascript
详解vue beforeRouteEnter 异步获取数据给实例问题
2019/08/09 Javascript
Vue学习之常用指令实例详解
2020/01/06 Javascript
解决js中的setInterval清空定时器不管用问题
2020/11/17 Javascript
python获取Linux下文件版本信息、公司名和产品名的方法
2014/10/05 Python
Python中处理字符串的相关的len()方法的使用简介
2015/05/19 Python
在Python中操作列表之List.pop()方法的使用
2015/05/21 Python
python的re正则表达式实例代码
2018/01/24 Python
python将excel转换为csv的代码方法总结
2019/07/03 Python
Pycharm简单使用教程(入门小结)
2019/07/04 Python
Django 自定义404 500等错误页面的实现
2020/03/08 Python
HTML5 实现一个访问本地文件的实例
2012/12/13 HTML / CSS
Born鞋子官网:Born Shoes
2017/04/06 全球购物
绢花、人造花和人造花卉:BLOOM
2019/08/07 全球购物
StudentUniverse英国:学生航班、酒店和旅游
2019/08/25 全球购物
Java面试题:请问一下代码输出是什么
2015/05/27 面试题
社区母亲节活动方案
2014/03/05 职场文书
观看《永远的雷锋》心得体会
2014/03/12 职场文书
市级三好学生评语
2014/12/29 职场文书
小班教师个人总结
2015/02/05 职场文书
小学班主任工作总结2015
2015/04/07 职场文书
婚宴父亲致辞
2015/07/27 职场文书
Java设计模式之代理模式
2022/04/22 Java/Android