Django文件存儲(一)預設存儲系統

来源:http://www.cnblogs.com/linxiyue/archive/2017/08/30/7442232.html
-Advertisement-
Play Games

Django預設使用的文件存儲系統'django.core.files.storage.FileSystemStorage'是一個本地存儲系統,由settings中的DEFAULT_FILE_STORAGE值確定。 class FileSystemStorage(location=None, bas ...


Django預設使用的文件存儲系統'django.core.files.storage.FileSystemStorage'是一個本地存儲系統,由settings中的DEFAULT_FILE_STORAGE值確定。

class FileSystemStorage(location=Nonebase_url=Nonefile_permissions_mode=Nonedirectory_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參數,修改創建文件的許可權。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Spire.Pdf: 註:pdf 顯示中文一定要設置相應的中文字體,其他外文類似。否則顯示為亂碼( 如果繁體的伺服器上生成的中文內容PDF文檔,在簡體操作系統保存或並傳給簡體系統上查看,會存在亂碼問題,這個需要考慮的) 安裝配置:PM> Install-Package Spire.PDF https ...
  • C# using 三種使用方式 http://www.cnblogs.com/dachengxiaomeng/p/7452021.html 1.using指令。 using 命名空間名字。例如: using System; 這樣可以在程式中直接用命令空間中的類型,而不必指定類型的詳細命名空間,類似於 ...
  • jQuery的方法連綴使用起來非常方便,可以簡化語句,讓代碼變得清晰簡潔。那C#的類方法能不能也實現類似的功能呢?基於這樣的疑惑,研究了一下jQuery的源代碼,發現就是需要方法連綴的函數方法最後返回對象本身即可。既然javascript可以,C#應該也是可以的。 為了驗證,編寫一個jQPerson ...
  • 最近在做項目進度管理時,想通過安裝net.sf.mpxj-for-csharp包讀取.mpp格式文件,通過Nuget線上安裝時,出現以下情況,無法安裝,故開啟離線安裝道路。 離線安裝步驟如下: 一、下載你需要安裝的離線包nupkg文件,可以在Nuget官網下載:https://www.nuget.o ...
  • 最近在開始一個微信開發,發現微信的Access_Token獲取每天次數是有限的,然後想到緩存,正好看到微信教程裡面推薦HttpRuntime.Cache緩存就順便看了下。 ...
  • //設置對話框的過濾條件 ofdSelectPic.Filter = "png文件(*.png)|*.png|jpg 文件(*.jpg)|*.jpg|所有文件(*.*)|*.*"; ofdSelectPic.Title = "打開圖片"; ofdSelectPic.FilterIndex = 2; ...
  • 在使用Entity Framework過程中,有時需要藉助工具生成Code First的代碼,而Entity Framework Reverse POCO Code First Generator是一款不錯的工具 在Visual Studio中,通過“工具”→“擴展和更新...”來安裝Entity ...
  • 游戲伺服器裡面總是有一大堆的配置文件需要讀取, 而且這些配置文件的讀取: * 要不然做成弱類型的, 就是一堆字元串或者數字, 不能看出來錯誤(需要重新檢測一次) * 要不然做成強類型的, 每種類型都需要自己Parse一下 我個人比較喜歡後者, 因為前者LoadConfig的代碼簡單, 但是寫邏輯的時 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...