如果你需要提供自定義文件存儲(chǔ) – 一個(gè)普遍的例子是在某個(gè)遠(yuǎn)程系統(tǒng)上儲(chǔ)存文件 – 你可以通過(guò)定義一個(gè)自定義的儲(chǔ)存類(lèi)來(lái)實(shí)現(xiàn)。你需要遵循以下步驟:
1. 你的自定義儲(chǔ)存類(lèi)必須是django.core.files.storage.Storage的子類(lèi):
from django.core.files.storage import Storage
class MyStorage(Storage):
...
2. Django必須能夠不帶任何參數(shù)來(lái)實(shí)例化你的儲(chǔ)存類(lèi)。這意味著任何設(shè)置都應(yīng)該從django.conf.settings中獲取。
from django.conf import settings
from django.core.files.storage import Storage
class MyStorage(Storage):
def __init__(self, option=None):
if not option:
option = settings.CUSTOM_STORAGE_OPTIONS
...
3. 你的儲(chǔ)存類(lèi)必須實(shí)現(xiàn) _open() 和 _save()方法,以及任何適合于你的儲(chǔ)存類(lèi)的其它方法。更多這類(lèi)方法請(qǐng)見(jiàn)下文。
另外,如果你的類(lèi)提供本地文件存儲(chǔ),它必須覆寫(xiě)path()方法。
4. 你的儲(chǔ)存類(lèi)必須是 可以析構(gòu)的,所以它在遷移中的一個(gè)字段上使用的時(shí)候可以被序列化。只要你的字段擁有自己可以序列化的參數(shù),你就可以為它使用django.utils.deconstruct.deconstructible類(lèi)裝飾器(這也是Django用在FileSystemStorage上的東西)。
默認(rèn)情況下,下面的方法會(huì)拋出NotImplementedError異常,并且必須覆寫(xiě)它們。
然而要注意,并不是這些方法全部都需要,可以故意省略一些??梢圆槐貙?shí)現(xiàn)每個(gè)方法而仍然能擁有一個(gè)可以工作的儲(chǔ)存類(lèi)。
比如,如果在特定的儲(chǔ)存后端中,列出內(nèi)容的開(kāi)銷(xiāo)比較大,你可以決定不實(shí)現(xiàn)Storage.listdir。
另一個(gè)例子是只處理寫(xiě)入文件的后端。這種情況下,你不需要實(shí)現(xiàn)上面的任意一種方法。
根本上來(lái)說(shuō),需要實(shí)現(xiàn)哪種方法取決于你。如果不去實(shí)現(xiàn)一些方法,你會(huì)得到一個(gè)不完整(可能是不能用的)的接口。
你也會(huì)經(jīng)常想要使用特意為自定義儲(chǔ)存對(duì)象設(shè)計(jì)的鉤子。它們是:
_open(name, mode='rb')
必需的。
被Storage.open()調(diào)用,這是儲(chǔ)存類(lèi)用于打開(kāi)文件的實(shí)際工具。它必須返回File對(duì)象,在大多數(shù)情況下,你會(huì)想要返回一些子類(lèi),它們實(shí)現(xiàn)了后端儲(chǔ)存系統(tǒng)特定的邏輯。
_save(name, content)
被Storage.save()調(diào)用。name必須事先通過(guò)get_valid_name() 和 get_available_name()過(guò)濾,并且content自己必須是一個(gè)File對(duì)象。
應(yīng)該返回被保存文件的真實(shí)名稱(通常是傳進(jìn)來(lái)的name,但是如果儲(chǔ)存需要修改文件名稱,則返回新的名稱來(lái)代替)。
get_valid_name(name)
返回適用于當(dāng)前儲(chǔ)存系統(tǒng)的文件名。傳遞給該方法的name參數(shù)是發(fā)送給服務(wù)器的原始文件名稱,并移除了所有目錄信息。你可以覆寫(xiě)這個(gè)方法,來(lái)自定義非標(biāo)準(zhǔn)的字符將會(huì)如何轉(zhuǎn)換為安全的文件名稱。
Storage提供的代碼只會(huì)保留原始文件名中的數(shù)字和字母字符、英文句號(hào)和下劃線,并移除其它字符。
get_available_name(name, max_length=None)
返回在儲(chǔ)存系統(tǒng)中可用的文件名稱,可能會(huì)顧及到提供的文件名稱。傳給這個(gè)方法的name參數(shù)需要事先過(guò)濾為儲(chǔ)存系統(tǒng)有效的文件名稱,根據(jù)上面描述的get_valid_name() 方法。
如果提供了max_length,文件名稱長(zhǎng)度不會(huì)超過(guò)它。如果不能找到可用的、唯一的文件名稱,會(huì)拋出SuspiciousFileOperation 異常。
如果name命名的文件已存在,一個(gè)下劃線加上隨機(jī)7個(gè)數(shù)字或字母的字符串會(huì)添加到文件名稱的末尾,擴(kuò)展名之前。
Changed in Django 1.7:
之前,下劃線和一位數(shù)字(比如"_1", "_2",以及其他)會(huì)添加到文件名稱的末尾,直到目標(biāo)目錄中發(fā)現(xiàn)了可用的名稱。一些惡意的用戶會(huì)利用這一確定性的算法來(lái)進(jìn)行dos攻擊。 這一變化也在1.6.6, 1.5.9, 和 1.4.14中出現(xiàn)。
Changed in Django 1.8:
新增了max_length參數(shù)。
自定義儲(chǔ)存系統(tǒng) 以相同方式工作:你可以把它們作為storage參數(shù)傳遞給FileField。
譯者:Django 文檔協(xié)作翻譯小組,原文:Custom storage。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。