Django文件存儲(chǔ) 默認(rèn)存儲(chǔ)系統(tǒng)解析
Django默認(rèn)使用的文件存儲(chǔ)系統(tǒng)'django.core.files.storage.FileSystemStorage'是一個(gè)本地存儲(chǔ)系統(tǒng),由settings中的DEFAULT_FILE_STORAGE值確定。
class FileSystemStorage(location=None, base_url=None, file_permissions_mode=None, directory_permissions_mode=None)
FileSystemStorage類繼承自Storage類,location是存儲(chǔ)文件的絕對(duì)路徑,默認(rèn)值是settings中的MEDIA_ROOT值,base_url默認(rèn)值是settings中的MEDIA_URL值。
當(dāng)定義location參數(shù)時(shí),可以無(wú)視MEDIA_ROOT值來(lái)存儲(chǔ)文件:
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)
這樣文件會(huì)存儲(chǔ)在/media/photos文件夾。
可以直接使用Django的文件存儲(chǔ)系統(tǒng)來(lái)存儲(chǔ)文件:
>>> 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方法看下上傳文件是怎么存儲(chǔ)的:
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('\\', '/'))
方法中可以看出,先判斷文件存儲(chǔ)的目錄是否存在,如果不存在,使用os.mkdirs()依次創(chuàng)建目錄。
根據(jù)directory_permissions_mode參數(shù)來(lái)確定創(chuàng)建的目錄的權(quán)限,應(yīng)該為(0777 &~umask)。
然后使用os.open()創(chuàng)建文件,flags參數(shù)為(os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0)),
這樣當(dāng)文件已存在時(shí),則報(bào)EEXIST異常,使用get_available_name()方法重新確定文件的名字。
mode為0o666,權(quán)限為(0666 &~umask)。
content為FILE對(duì)象,如一切正常,使用FILE.chunks()依次將內(nèi)容寫入文件。
最后,根據(jù)file_permissions_mode參數(shù),修改創(chuàng)建文件的權(quán)限。
相關(guān)文章
python實(shí)現(xiàn)超簡(jiǎn)單的視頻對(duì)象提取功能
這篇文章主要給大家介紹了關(guān)于利用python實(shí)現(xiàn)超簡(jiǎn)單的視頻對(duì)象提取功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06
深度學(xué)習(xí)Tensorflow?2.4?完成遷移學(xué)習(xí)和模型微調(diào)
這篇文章主要為大家介紹了深度學(xué)習(xí)Tensorflow?2.4?完成遷移學(xué)習(xí)和模型微調(diào),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
python3實(shí)現(xiàn)ftp服務(wù)功能(服務(wù)端 For Linux)
這篇文章主要介紹了python3實(shí)現(xiàn)ftp服務(wù)功能,服務(wù)端 For Linux,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Python實(shí)現(xiàn)模擬瀏覽器請(qǐng)求及會(huì)話保持操作示例
這篇文章主要介紹了Python實(shí)現(xiàn)模擬瀏覽器請(qǐng)求及會(huì)話保持操作,結(jié)合實(shí)例形式分析了Python基于urllib與urllib2模塊模擬瀏覽器請(qǐng)求及cookie保存會(huì)話相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
基于python+pandoc實(shí)現(xiàn)html批量轉(zhuǎn)word
pandoc是一個(gè)強(qiáng)大的文檔格式轉(zhuǎn)換工具,支持豐富的格式轉(zhuǎn)換,并盡可能的保留原來(lái)的排版,號(hào)稱文檔格式轉(zhuǎn)換的瑞士軍刀,本文將給大家介紹一下使用python搭配pandoc實(shí)現(xiàn)html批量轉(zhuǎn)word,感興趣的朋友可以參考閱讀下2023-09-09
python中split(),?os.path.split()和os.path.splitext()的用法
本文主要介紹了python中split(),?os.path.split()和os.path.splitext()的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
詳解Python 模擬實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式的實(shí)例
這篇文章主要介紹了詳解Python 模擬實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式的實(shí)例的相關(guān)資料,這里使用了線程知識(shí),隊(duì)列知識(shí)及循環(huán)的知識(shí),需要的朋友可以參考下2017-08-08
Matplotlib繪圖基礎(chǔ)之配置參數(shù)詳解
Matplotlib?提供了大量配置參數(shù),這些參數(shù)可以但不限于讓我們從整體上調(diào)整通過(guò)?Matplotlib?繪制的圖形樣式,下面我們就來(lái)看看如何巧妙的運(yùn)用這些參數(shù)吧2023-08-08
django項(xiàng)目中使用手機(jī)號(hào)登錄的實(shí)例代碼
這篇文章主要介紹了django項(xiàng)目中使用手機(jī)號(hào)登錄的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-08-08
構(gòu)建高效的python requests長(zhǎng)連接池詳解
這篇文章主要介紹了構(gòu)建高效的python requests長(zhǎng)連接池詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05

