這篇文檔描述了Django為那些用戶上傳文件準(zhǔn)備的文件訪問API。底層的API足夠通用,你可以使用為其它目的來使用它們。如果你想要處理靜態(tài)文件(JS,CSS,以及其他),參見管理靜態(tài)文件(CSS和圖像)。
通常,Django使用MEDIA_ROOT和 MEDIA_URL設(shè)置在本地儲(chǔ)存文件。下面的例子假設(shè)你使用這些默認(rèn)值。
然而,Django提供了一些方法來編寫自定義的 文件儲(chǔ)存系統(tǒng),允許你完全自定義Django在哪里以及如何儲(chǔ)存文件。這篇文檔的另一部分描述了這些儲(chǔ)存系統(tǒng)如何工作。
當(dāng)你使用FileField 或者 ImageField的時(shí)候,Django為你提供了一系列的API用來處理文件。
考慮下面的模型,它使用ImageField來儲(chǔ)存一張照片:
from django.db import models
class Car(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=5, decimal_places=2)
photo = models.ImageField(upload_to='cars')
任何Car的實(shí)例都有一個(gè) photo字段,你可以通過它來獲取附加圖片的詳細(xì)信息:
>>> car = Car.objects.get(name="57 Chevy")
>>> car.photo
<ImageFieldFile: chevy.jpg>
>>> car.photo.name
'cars/chevy.jpg'
>>> car.photo.path
'/media/cars/chevy.jpg'
>>> car.photo.url
'http://media.example.com/cars/chevy.jpg'
例子中的car.photo 對(duì)象是一個(gè)File 對(duì)象,這意味著它擁有下面描述的所有方法和屬性。
注意
文件保存是數(shù)據(jù)庫模型保存的一部分,所以磁盤上真實(shí)的文件名在模型保存之前并不可靠。
例如,你可以通過設(shè)置文件的 name屬性為一個(gè)和文件儲(chǔ)存位置 (MEDIA_ROOT,如果你使用默認(rèn)的FileSystemStorage)相關(guān)的路徑,來修改文件名稱。
>>> import os
>>> from django.conf import settings
>>> initial_path = car.photo.path
>>> car.photo.name = 'cars/chevy_ii.jpg'
>>> new_path = settings.MEDIA_ROOT + car.photo.name
>>> # Move the file on the filesystem
>>> os.rename(initial_path, new_path)
>>> car.save()
>>> car.photo.path
'/media/cars/chevy_ii.jpg'
>>> car.photo.path == new_path
True
當(dāng)Django需要表示一個(gè)文件的時(shí)候,它在內(nèi)部使用django.core.files.File實(shí)例。這個(gè)對(duì)象是 Python 內(nèi)建文件對(duì)象的一個(gè)簡單封裝,并帶有一些Django特定的附加功能。
大多數(shù)情況你可以簡單地使用Django提供給你的File對(duì)象(例如像上面那樣把文件附加到模型,或者是上傳的文件)。
如果你需要自行構(gòu)造一個(gè)File對(duì)象,最簡單的方法是使用Python內(nèi)建的file 對(duì)象來創(chuàng)建一個(gè):
>>> from django.core.files import File
# Create a Python file object using open()
>>> f = open('/tmp/hello.world', 'w')
>>> myfile = File(f)
現(xiàn)在你可以使用 File類的任何文檔中記錄的屬性和方法了。
注意這種方法創(chuàng)建的文件并不會(huì)自動(dòng)關(guān)閉。以下步驟可以用于自動(dòng)關(guān)閉文件:
>>> from django.core.files import File
# Create a Python file object using open() and the with statement
>>> with open('/tmp/hello.world', 'w') as f:
... myfile = File(f)
... myfile.write('Hello World')
...
>>> myfile.closed
True
>>> f.closed
True
在處理大量對(duì)象的循環(huán)中訪問文件字段時(shí),關(guān)閉文件極其重要。如果文件在訪問之后沒有手動(dòng)關(guān)閉,會(huì)有消耗完文件描述符的風(fēng)險(xiǎn)。這可能導(dǎo)致如下錯(cuò)誤:
IOError: [Errno 24] Too many open files
在背后,Django需要決定在哪里以及如何將文件儲(chǔ)存到文件系統(tǒng)。這是一個(gè)對(duì)象,它實(shí)際上理解一些東西,比如文件系統(tǒng),打開和讀取文件,以及其他。
Django的默認(rèn)文件儲(chǔ)存由DEFAULT_FILE_STORAGE設(shè)置提供。如果你沒有顯式提供一個(gè)儲(chǔ)存系統(tǒng),就會(huì)使用它。
關(guān)于內(nèi)建的默認(rèn)文件儲(chǔ)存系統(tǒng)的細(xì)節(jié),請(qǐng)參見下面一節(jié)。另外,關(guān)于編寫你自己的文件儲(chǔ)存系統(tǒng)的一些信息,請(qǐng)見編寫自定義的文件系統(tǒng)。
大多數(shù)情況你可能并不想使用File對(duì)象(它向文件提供適當(dāng)?shù)拇鎯?chǔ)功能),你可以直接使用文件儲(chǔ)存系統(tǒng)。你可以創(chuàng)建一些自定義文件儲(chǔ)存類的實(shí)例,或者 – 大多數(shù)情況更加有用的 – 你可以使用全局的默認(rèn)儲(chǔ)存系統(tǒng):
>>> 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
關(guān)于文件儲(chǔ)存API,參見 文件儲(chǔ)存API。
Django自帶了django.core.files.storage.FileSystemStorage 類,它實(shí)現(xiàn)了基本的本地文件系統(tǒng)中的文件儲(chǔ)存。
例如,下面的代碼會(huì)在 /media/photos 目錄下儲(chǔ)存上傳的文件,無論MEDIA_ROOT設(shè)置是什么:
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)
自定義儲(chǔ)存系統(tǒng) 以相同方式工作:你可以把它們作為storage參數(shù)傳遞給FileField。
譯者:Django 文檔協(xié)作翻譯小組,原文:Managing files。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。